package com.bsoft.gol.hcs.specialist.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bsoft.gol.hcs.common.bean.response.ParameterResponse;
import com.bsoft.gol.hcs.common.service.ICommonService;
import com.bsoft.gol.hcs.enumcase.*;
import com.bsoft.gol.hcs.followup.bean.request.DeleteFollowUpFormDTO;
import com.bsoft.gol.hcs.followup.bean.request.FollowUpEducationDTO;
import com.bsoft.gol.hcs.followup.bean.request.FollowUpQuestionnaireDTO;
import com.bsoft.gol.hcs.followup.bean.request.SaveFollowUpFormDTO;
import com.bsoft.gol.hcs.followup.bean.response.AuthFollowUpRouteVO;
import com.bsoft.gol.hcs.followup.bean.response.FollowUpEducationVO;
import com.bsoft.gol.hcs.followup.bean.response.HangUpFollowUpListVO;
import com.bsoft.gol.hcs.followup.dao.FusAfterHosRecordDAO;
import com.bsoft.gol.hcs.his.service.SendMsgService;
import com.bsoft.gol.hcs.odshmrecord.dao.OdsHmDiseaseRelationDAO;
import com.bsoft.gol.hcs.satisfaction.bean.vo.QueryRouteQuestionListVO;
import com.bsoft.gol.hcs.specialist.bean.request.*;
import com.bsoft.gol.hcs.specialist.bean.response.*;
import com.bsoft.gol.hcs.specialist.bean.vo.ExamReportVo;
import com.bsoft.gol.hcs.specialist.bean.vo.FollowUpRecordsVO;
import com.bsoft.gol.hcs.specialist.bean.vo.QuestionVo;
import com.bsoft.gol.hcs.specialist.bean.vo.VrInpatientVisitRecordVo;
import com.bsoft.gol.hcs.specialist.dao.*;
import com.bsoft.gol.hcs.specialist.entity.*;
import com.bsoft.gol.hcs.specialist.service.IFollowUpCommonService;
import com.bsoft.gol.hcs.specialist.service.IFollowUpPlanService;
import com.bsoft.gol.hcs.utils.*;
import com.bsoft.gol.hcs.visitrecord.dao.VrVisitDiagnosisDAO;
import com.bsoft.gol.hcs.visitrecord.entity.VrSurgicalRecord;
import com.bsoft.gol.hcs.visitrecord.entity.VrVisitDiagnosis;
import com.bsoft.gol.mpi.model.Certificate;
import com.bsoft.gol.mpi.model.Person;
import com.bsoft.gol.mpi.provider.IMPIProvider;
import com.bsoft.gol.mpi.service.MPIException;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import ctd.account.UserRoleToken;
import ctd.controller.exception.ControllerException;
import ctd.spring.boot.annotation.SsdevReference;
import ctd.spring.boot.annotation.SsdevService;
import ctd.util.AppContextHolder;
import ctd.util.KeyGenerator;
import ctd.util.annotation.RpcService;
import hcn.annotation.UserEventTracking;
import hcn.base.Organization;
import hcn.base.VrOutpatientVisitRecord;
import hcn.bean.UserAllVo;
import hcn.bean.specialist.qo.GroupMemberRequest;
import hcn.bean.specialist.vo.ChronicTeamList;
import hcn.enums.CollectionInfoIdTypeEnum;
import hcn.enums.CollectionInfoTypeEnum;
import hcn.enums.ItemTypeEnum;
import hcn.service.base.IOrgDoctorsService;
import hcn.service.commonClinical.qo.SysParameterRequest;
import hcn.specialist.DiseaseSpecies;
import hcn.specialist.DocTeamFusAuthority;
import hcn.util.BaseResponse;
import hcn.util.ResultCode;
import hcn.util.RpcUserToken;
import org.apache.commons.lang3.StringUtils;
import org.atag.core.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import pcn.service.DocIdentityService;
import pcn.service.web.BaseDeviceService;
import service.rpc.IDocTeamMemberRpcService;
import service.rpc.IDocTeamRpcService;
import service.rpc.IOrganizationRpcService;
import ssdev.bbp.person.IPersonService;

import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author tongtp
 * @version v0.1
 * @className FollowUpPlanServiceImpl
 * @description 随访计划服务
 * @create 2020-07-21 14:20
 **/
@SsdevService(id = "followUpPlan" ,name="followUpPlanService")
public class FollowUpPlanServiceImpl implements IFollowUpPlanService {

    private final static Logger logger = LoggerFactory.getLogger(FollowUpPlanServiceImpl.class);
    @Value("${database_type}")
    public String databaseType;//1.mysql  2.达梦    默认mysql
    @Autowired
    DiseaseSpeciesDAO diseaseSpeciesDAO;
    @Value("${admin_user_id}")
    private String adminUserId;
    @Autowired
    private FollowUpRouteDAO followUpRouteDAO;
    @Autowired
    private FollowUpRecordsDAO followUpRecordsDAO;
    @Autowired
    private FollowUpRouteDetailDAO followUpRouteDetailDAO;
    @Autowired
    private FollowUpRouteDetailContentDAO followUpRouteDetailContentDAO;
    @Autowired
    private FollowUpRouteDetailFactorDAO followUpRouteDetailFactorDAO;
    //表单和推荐科室保存dao
    @Autowired
    FollowUpRouteDetailFormDAO followUpRouteDetailFormDAO;
    //开始结束因素存储关联表dao
    @Autowired
    FollowUpRouteDetailFactorRelationDAO followUpRouteDetailFactorRelationDAO;
    @Autowired
    private FollowUpRecordsContentDAO followUpRecordsContentDAO;
    @Autowired
    private ProduceExecutionListDAO produceExecutionListDAO;
    @Autowired
    private IDocTeamMemberRpcService docTeamMemberRpcService;
    @Autowired
    private IDocTeamRpcService docTeamRpcService;
    @Autowired
    private FollowUpPlanProduceRecordDAO followUpPlanProduceRecordDAO;
    @Autowired
    private FusTeamChronicGroupRecordDAO fusTeamChronicGroupRecordDAO;
    @Autowired
    private SendMsgService sendMsgService;
    @Autowired
    private ICommonService commonService;
    @Autowired
    private IOrganizationRpcService organizationRpcService;
    @Autowired
    private PatientMedicalDataCollectDAO patientMedicalDataCollectDAO;
    @Autowired
    private OdsHmDiseaseRelationDAO odsHmDiseaseRelationDAO;
    @Autowired
    private VrVisitDiagnosisDAO vrVisitDiagnosisDAO;
    @Value("${project_source}")
    private String projectSource;
    @Autowired
    private FusAnswerCheckReportInfoDAO fusAnswerCheckReportInfoDAO;
    @Autowired
    private FusAnswerDiagnosisInfoDAO fusAnswerDiagnosisInfoDAO;
    @Autowired
    private FusAnswerDrugInfoDAO fusAnswerDrugInfoDAO;
    @Autowired
    private FusAnswerInHospitalInfoDAO fusAnswerInHospitalInfoDAO;
    @Autowired
    private FusAnswerInspectionReportInfoDAO fusAnswerInspectionReportInfoDAO;
    @Autowired
    private FusAnswerOperativeInfoDAO fusAnswerOperativeInfoDAO;
    @Autowired
    private FusAnswerOutpatientInfoDAO fusAnswerOutpatientInfoDAO;
    @Autowired
    private FusAnswerTreatmentInfoDAO fusAnswerTreatmentInfoDAO;
    @Autowired
    private FusAnswerRouteRecordDAO fusAnswerRouteRecordDAO;
    @Autowired
    private DiseasePeriodDAO diseasePeriodDAO;
    @Autowired
    private FollowUpStateDao followUpStateDao;
    @Autowired
    private FollowUpPathRouteDAO followUpPathRouteDAO;
    @Autowired
    private FollowPlanDAO followPlanDAO;
    @Autowired
    private FollowUpPathRouteExplandDAO followUpPathRouteExplandDAO;
    @Autowired
    private FollowPatientLabelDAO followPatientLabelDAO;
    @Autowired
    private IFollowUpCommonService followUpCommonService;
    @Autowired
    private FusAfterHosRecordDAO fusAfterHosRecordDAO;
    @Autowired
    private FusAfterPendingRecordDAO fusAfterPendingRecordDAO;
    @Autowired
    private FusAfterContactsDAO fusAfterContactsDAO;
    @Autowired
    private FollowUpRecordsEducationDAO followUpRecordsEducationDAO;
    @Autowired
    private FollowUpRecordsRequisitionDAO followUpRecordsRequisitionDAO;
    @SsdevReference("hcn.baseDeviceService")
    private BaseDeviceService baseDeviceService;
    @Autowired
    private DocTeamFusAuthorityDAO docTeamFusAuthorityDAO;
    @Autowired
    private FusHealthEducationDAO fusHealthEducationDAO;
    @SsdevReference("mpi.mpiProvider")
    private IMPIProvider mpiProvider;
    @Autowired
    private FollowUpRecordsExtendDAO followUpRecordsExtendDAO;
    @Autowired
    private DocTeamDiseaseDAO docTeamDiseaseDAO;
    @Autowired
    private FusAfterRequisitionRecordDAO fusAfterRequisitionRecordDAO;
    @Autowired
    private FusAfterHealthEducationDAO fusAfterHealthEducationDAO;
    @SsdevReference("hcn.orgDoctorsService")
    private IOrgDoctorsService orgDoctorsService;

    @SsdevReference("hcn.docIdentityService")
    private DocIdentityService docIdentityService;

    /**
     * @param request
     * @throws
     * @description: 新增随访计划记录
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/8/11 9:25
     * @deprecated see {@link FollowUpPlanServiceImpl#addPlan(AddFusPlanRequest)}
     */
    @Override
    @RpcService
    @Deprecated
    public List<Long> addExecutionList(AddExecutionListRequest request) throws ControllerException {
        List<Long> recordIdList = new ArrayList<>();
        if (CommonUtils.isEmpty(request.getDiseaseTypeId())) {
            throw new ControllerException(ResultCode.ERROR, "入参不能为空");
        }
//		查询病种信息
        DiseaseSpecies diseaseSpecies = diseaseSpeciesDAO.get(request.getDiseaseTypeId());
        if (diseaseSpecies == null) {
            throw new ControllerException("病种不存在");
        }
        Long[] teamChronicGroupIdList = request.getTeamChronicGroupIdList();
        for (Long teamChronicGroupIdEnter :
                teamChronicGroupIdList) {
            Long teamChronicGroupId = fusTeamChronicGroupRecordDAO.queryTeamChronicGroupId(request.getDiseaseTypeId(),
                    teamChronicGroupIdEnter);
            if (teamChronicGroupId == null) {
                throw new ControllerException("对应的病种没有找到有效的入组记录");
            }
            FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord =
                    fusTeamChronicGroupRecordDAO.get(teamChronicGroupId);
            if (fusTeamChronicGroupRecord == null) {
                throw new ControllerException("入组记录不存在");
            }
            //随访提前通知时间-天数
            Integer advanceNotifyDate = 1;
            if (Byte.valueOf("1").equals(request.getIsNotify()) && Objects.nonNull(request.getNotifyDate())) {
                advanceNotifyDate = followUpCommonService.getAdvanceNotifyDate(advanceNotifyDate, request.getNotifyDate());
                if (advanceNotifyDate > 0) {
                    throw new ControllerException("通知患者时间为字典之外的值，新增随访计划失败");
                }
            }

            request.setFollowUpStatus(Byte.valueOf(Constants.ZORE_STRING));
            FollowUpRecords followUpRecords = saveFollowUpRecords(request, diseaseSpecies, fusTeamChronicGroupRecord,
                    advanceNotifyDate);
            //保存推荐科室信息
            if (CommonUtils.isNotEmpty(request.getRecommendDeptObj())) {
                saveFactorListByRecommendDept(request.getRecommendDeptObj(), followUpRecords.getOrganizationId(), followUpRecords.getRecordId());
            }
            recordIdList.add(followUpRecords.getRecordId());

        }
        return recordIdList;
    }

    /**
     * 手动添加医护随访计划
     */
    @Override
    @RpcService
    public List<Long> addPlan(AddFusPlanRequest request) {
        List<Long> recordIdList = new ArrayList<>();
        DiseaseSpecies diseaseSpecies = diseaseSpeciesDAO.get(request.getDiseaseTypeId());
        if (diseaseSpecies == null) {
            throw new ServiceException("病种不存在");
        }
        UserAllVo allByOnline = baseDeviceService.getAllByOnline();
        String operatorId = request.getOperatorId();
        if (Objects.nonNull(allByOnline) && StringUtils.isEmpty(operatorId)) {
            request.setOperatorId(allByOnline.getLocalDoctorId());
        }
        Long[] teamChronicGroupIdList = request.getTeamChronicGroupIdList();
        for (Long teamChronicGroupIdEnter : teamChronicGroupIdList) {
            Long teamChronicGroupId = fusTeamChronicGroupRecordDAO.queryTeamChronicGroupId(request.getDiseaseTypeId(),
                    teamChronicGroupIdEnter);
            if (teamChronicGroupId == null) {
                throw new ServiceException("对应的病种没有找到有效的入组记录");
            }
            FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord =
                    fusTeamChronicGroupRecordDAO.get(teamChronicGroupId);
            if (fusTeamChronicGroupRecord == null) {
                throw new ServiceException("入组记录不存在");
            }
            //随访提前通知时间-天数
            Integer advanceNotifyDate = 1;
            if (Byte.valueOf("1").equals(request.getIsNotify()) && Objects.nonNull(request.getNotifyDate())) {
                advanceNotifyDate = followUpCommonService.getAdvanceNotifyDate(advanceNotifyDate, request.getNotifyDate());
                if (advanceNotifyDate > 0) {
                    throw new ServiceException("通知患者时间为字典之外的值，新增随访计划失败");
                }
            }

//            request.setFollowUpStatus(Byte.valueOf(Constants.ZORE_STRING));
            FollowUpRecords followUpRecords = saveMedicalFollowUpRecords(request, diseaseSpecies, advanceNotifyDate, fusTeamChronicGroupRecord);
            recordIdList.add(followUpRecords.getRecordId());

        }

        return recordIdList;


    }

    private FollowUpRecords saveMedicalFollowUpRecords(AddFusPlanRequest request, DiseaseSpecies diseaseSpecies, Integer advanceNotifyDate, FusTeamChronicGroupRecordEntity groupRecord) {
        Date now = new Date();
        FollowUpRecords followUpRecords = new FollowUpRecords();
        followUpRecords.setDiseaseTypeId(diseaseSpecies.getDiseaseTypeId());
        followUpRecords.setDiseaseTypeName(diseaseSpecies.getDiseaseTypeName());
        //随访状态：0未随访 1 已随访 9 已终止
        followUpRecords.setFollowUpStatus((byte) 0);
        followUpRecords.setCreateId(request.getOperatorId());
        //通知状态：0 未通知 1 已通知
        followUpRecords.setNotifyStatus((byte) 0);
        followUpRecords.setRouteDetailType(Byte.parseByte(request.getRouteDetailType()));
        followUpRecords.setIsNotify(request.getIsNotify());
        followUpRecords.setPlanTime(request.getPlanTime());
        //是否通知患者，0不通知，1通知
        if (request.getIsNotify() == (byte) 1) {
            Calendar advanceNotifyDateInstance = Calendar.getInstance();
            advanceNotifyDateInstance.setTime(followUpRecords.getPlanTime());
            advanceNotifyDateInstance.add(Calendar.DAY_OF_YEAR, advanceNotifyDate);
            followUpRecords.setPlanNotifyDate(advanceNotifyDateInstance.getTime());
        }
        followUpRecords.setMedicalRecordId(request.getMedicalRecordId());
        followUpRecords.setMedicalRecordName(request.getMedicalRecordName());
        followUpRecords.setOrganizationId(groupRecord.getOrganizationId());
        followUpRecords.setDepartmentId(groupRecord.getDepartmentId());
        followUpRecords.setDepartmentName(groupRecord.getDepartmentName());
        followUpRecords.setDoctorId(groupRecord.getDoctorId());
        followUpRecords.setDocId(groupRecord.getDocId());
        followUpRecords.setDoctorName(groupRecord.getDoctorName());
        followUpRecords.setPatientId(groupRecord.getPatientId());
        followUpRecords.setCardType(groupRecord.getCardType());
        followUpRecords.setCardNumber(groupRecord.getCardNumber());
        followUpRecords.setPatientName(groupRecord.getPersonName());
        followUpRecords.setPatientSex(groupRecord.getPersonSex());
        followUpRecords.setPatientMedicalCardType(groupRecord.getPatientMedicalCardType());
        followUpRecords.setPatientMedicalCardNumber(groupRecord.getPatientMedicalCardNumber());
        followUpRecords.setPatientAge(groupRecord.getAge() == null ? null :
                groupRecord.getAge().intValue());
        followUpRecords.setTelephone(groupRecord.getTelephone());
        followUpRecords.setCreateTime(now);
        followUpRecords.setTeamChronicGroupId(groupRecord.getTeamChronicGroupId());
        followUpRecords.setMedicalTeamId(groupRecord.getMedicalTeamId());
        followUpRecords.setMedicalTeamName(groupRecord.getMedicalTeamName());
        followUpRecords.setGmtCreate(now);
        followUpRecords.setGmtModified(now);
        followUpRecords.setAbnormalReadFlag(Constants.ZORE_STRING);
        followUpRecords.setAnswerAbnormal(Constants.TWO_STRING);
        followUpRecords.setAutoCreateFlag("0");
        followUpRecords.setAuditStatus((byte) 0);
        followUpRecords.setRouteId(request.getRouteId());
        followUpRecords.setRouteName(request.getRouteName());
        followUpRecordsDAO.save(followUpRecords);
        Long recordId = followUpRecords.getRecordId();

        //保存表单
        List<FollowUpQuestionnaireDTO> qList = request.getQuestionnaireList();
        if (!CollectionUtils.isEmpty(qList)) {
            qList.forEach(q -> {
                FollowUpRecordsRequisition insert = new FollowUpRecordsRequisition();
                insert.setFormId(KeyGenerator.randomGenerate());
                insert.setRecordId(recordId);
                insert.setCreateId(request.getOperatorId());
                insert.setExecuteId(request.getOperatorId());
                insert.setExecuteName("");
                insert.setCreateDt(new Date());
                insert.setModifyDt(new Date());
                insert.setQuestionnaireId(q.getQuestionnaireId());
                insert.setQuestionnaireName(q.getQuestionnaireName());
                insert.setUserInfoId("");
                followUpRecordsRequisitionDAO.insertSelective(insert);
            });
        }
        //保存健康监测
        List<FollowUpRouteDetailForm> detailForms = request.getFollowUpRouteDetailForms();
        if (!CollectionUtils.isEmpty(detailForms)){
            detailForms.forEach(f->{
                if (f.getItemType()==4){
                    //健康监测项
                    FollowUpRecordsExtendEntity extendEntity = new FollowUpRecordsExtendEntity();
                    extendEntity.setRecordId(recordId);
                    extendEntity.setDiseaseTypeId(diseaseSpecies.getDiseaseTypeId());
                    extendEntity.setDiseaseTypeName(diseaseSpecies.getDiseaseTypeName());
                    extendEntity.setTeamChronicGroupId(groupRecord.getTeamChronicGroupId());
                    extendEntity.setItemType(f.getItemType());
                    extendEntity.setMonitorId(f.getMonitorId());
                    extendEntity.setMonitorName(f.getMonitorName());
                    extendEntity.setFormRecordId(f.getFormRecordId());
                    extendEntity.setFormName(f.getFormName());
                    followUpRecordsExtendDAO.save(extendEntity);
                }
            });
        }

        //保存宣教
        List<FollowUpEducationDTO> eList = request.getEducationList();
        if (!CollectionUtils.isEmpty(eList)) {
            eList.forEach(e -> {
                FollowUpRecordsEducation insert = new FollowUpRecordsEducation();
                insert.setId(KeyGenerator.randomGenerate());
                insert.setRecordId(recordId);
                insert.setEducationId(e.getEducationId());
                insert.setEducationName(e.getEducationName());
                insert.setDefaultPush(0);
                insert.setCreateDt(new Date());
                insert.setModifyDt(new Date());
                followUpRecordsEducationDAO.insertSelective(insert);
            });
        }
        List<FollowUpRouteDetailContent> followUpList = request.getFollowUpList();
        if (!CollectionUtils.isEmpty(followUpList)){
            followUpList.forEach(e->{
                FollowUpRecordsContent insert = new FollowUpRecordsContent();
                insert.setRecordId(recordId);
                insert.setIndexType(e.getIndexType());
                insert.setIndexClassifyId(e.getIndexClassifyId());
                insert.setIndexClassifyName(e.getIndexClassifyName());
                insert.setBusinessId(e.getBusinessId());
                insert.setBusinessName(e.getBusinessName());
                insert.setProjectDetails(e.getProjectDetails());
                followUpRecordsContentDAO.insertSelective(insert);
            });

        }


        return followUpRecords;
    }


    /**
     * 获取病种关联的路径, 同时根据医生有权限的路径进行过滤
     */
    @RpcService
    @Override
    public List<AuthFollowUpRouteVO> getDiseaseRoute(Long diseaseTypeId) throws ControllerException {
        UserAllVo user = baseDeviceService.getAllByOnline();
        String doctorId = user.getDoctorId();
        if (StringUtils.isEmpty(doctorId)) {
            return Collections.emptyList();
        }
        List<FollowUpRoute> routeList = followUpRouteDAO.queryByDiseaseTypeId(diseaseTypeId);
        if (CollectionUtils.isEmpty(routeList)) {
            return Collections.emptyList();
        }
        GroupMemberRequest request = new GroupMemberRequest();
        request.setDocId(doctorId);
        request.setTeamType(FollowTypeEnum.FUS_SATISFACTION.getType());
        List<Long> teamIdList = docTeamRpcService.queryTeamIdList(request);
        List<DocTeamFusAuthority> docTeamFusAuthorities = docTeamFusAuthorityDAO.queryByDocId(doctorId, teamIdList);
//        if(CollectionUtils.isEmpty(docTeamFusAuthorities)){
//            return Collections.emptyList();
//        }
//        Map<Long, Long> collect = docTeamFusAuthorities.stream().collect(Collectors.toMap(DocTeamFusAuthority::getRouteId, DocTeamFusAuthority::getRouteId, (v1, v2) -> v1));
        return routeList.stream()
                .map(r -> {
                    AuthFollowUpRouteVO vo = new AuthFollowUpRouteVO();
                    vo.setRouteId(r.getRouteId().toString());
                    vo.setRouteName(r.getRouteName());
                    vo.setDiseaseTypeId(r.getDiseaseTypeId());
                    return vo;
                }).collect(Collectors.toList());
        //AuthFollowUpRouteVO
    }


    /**
     * 根据路径id查询其所有子路径中包含的表单与宣教信息
     */
    @Override
    @RpcService
    public QueryRouteQuestionListVO getRouteForm(Long routeId) {
        List<FollowUpRouteDetailForm> ques = followUpRouteDetailFormDAO.queryByRouteId(routeId, ItemTypeEnum.FORM.getType());
        List<FollowUpRouteDetailForm> edu = followUpRouteDetailFormDAO.queryByRouteId(routeId, ItemTypeEnum.EDUCATION.getType());
        List<QueryRouteQuestionListVO.Form> questionList = new ArrayList<>();
        List<QueryRouteQuestionListVO.Form> educationList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(ques)) {
            //去重
            questionList = ques.stream().collect(Collectors.toMap(FollowUpRouteDetailForm::getFormRecordId, r -> r, (v1, v2) -> v1))
                    .entrySet().stream().map(Map.Entry::getValue)
                    .map(r -> {
                        QueryRouteQuestionListVO.Form f = new QueryRouteQuestionListVO.Form();
                        f.setQuestionnaireId(r.getFormRecordId());
                        f.setQuestionnaireName(r.getFormName());
                        return f;
                    })
                    .collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(edu)) {
            //去重
            educationList = edu.stream().collect(Collectors.toMap(FollowUpRouteDetailForm::getEducationId, r -> r, (v1, v2) -> v1))
                    .entrySet().stream().map(Map.Entry::getValue)
                    .map(r -> {
                        QueryRouteQuestionListVO.Form f = new QueryRouteQuestionListVO.Form();
                        Long educationId = r.getEducationId();
                        if (Objects.isNull(educationId)) {
                            return null;
                        }
                        f.setEducationId(educationId.toString());
                        f.setEducationName(r.getEducationName());
                        return f;
                    }).filter(Objects::nonNull)
                    .collect(Collectors.toList());
        }
        QueryRouteQuestionListVO vo = new QueryRouteQuestionListVO();
        vo.setQuestionList(questionList);
        vo.setEducationList(educationList);
        return vo;
    }

    /**
     * 推荐科室保存方法
     *
     * @param recommendDept
     * @param orgId
     * @param recordId
     */
    private void saveFactorListByRecommendDept(List<FollowUpRouteDetailRecommendDeptReq> recommendDept, String orgId, Long recordId) {

        for (FollowUpRouteDetailRecommendDeptReq deptReq : recommendDept) {
            FollowUpRouteDetailForm followUpRouteDetailForm = new FollowUpRouteDetailForm();
            followUpRouteDetailForm.setOrganizationId(orgId);
            //TODO 这里保存的时候是否能获取到路径id和路径详情id 暂时注释set
//            followUpRouteDetailForm.setRouteId(routeId);
//            followUpRouteDetailForm.setRouteDetailId(routeDetailId);
            followUpRouteDetailForm.setItemType((byte) 2);
            followUpRouteDetailForm.setDeptType(deptReq.getFactorType());
            followUpRouteDetailForm.setParentDeptCode(deptReq.getParentDepartmentCode());
            followUpRouteDetailForm.setParentDeptName(deptReq.getParentDepartmentName());
            followUpRouteDetailForm.setDeptCode(deptReq.getDepartmentCode());
            followUpRouteDetailForm.setDeptName(deptReq.getDepartmentName());
            followUpRouteDetailFormDAO.save(followUpRouteDetailForm);
        }

    }

    /**
     * @param request
     * @param diseaseSpecies
     * @param fusTeamChronicGroupRecord
     * @param advanceNotifyDate
     * @throws
     * @description: 保存随访计划记录
     * @return: specialist.entity.FollowUpRecords
     * @author: tongtp
     * @date: 2020/8/11 16:08
     */
    @Override
    public FollowUpRecords saveFollowUpRecords(AddExecutionListRequest request, DiseaseSpecies diseaseSpecies,
                                               FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord,
                                               Integer advanceNotifyDate) throws ControllerException {
        //表单id
        String medicalRecordId = request.getMedicalRecordId();
        //表单名称
        String medicalRecordName = request.getMedicalRecordName();
        Date now = new Date();
        FollowUpRecords followUpRecords = new FollowUpRecords();
        followUpRecords.setDiseaseTypeId(diseaseSpecies.getDiseaseTypeId());
        followUpRecords.setDiseaseTypeName(diseaseSpecies.getDiseaseTypeName());
        //随访状态：0未随访 1 已随访 9 已终止
        followUpRecords.setFollowUpStatus(request.getFollowUpStatus());
        followUpRecords.setCreateId(request.getOperatorId());
        //通知状态：0 未通知 1 已通知
        followUpRecords.setNotifyStatus((byte) 0);
        followUpRecords.setRouteDetailType(request.getRouteDetailType());
        followUpRecords.setIsNotify(request.getIsNotify());
        followUpRecords.setPlanTime(request.getPlanTime());
        //是否通知患者，0不通知，1通知
        if (request.getIsNotify() == (byte) 1) {
            Calendar advanceNotifyDateInstance = Calendar.getInstance();
            advanceNotifyDateInstance.setTime(followUpRecords.getPlanTime());
            advanceNotifyDateInstance.add(Calendar.DAY_OF_YEAR, advanceNotifyDate);
            followUpRecords.setPlanNotifyDate(advanceNotifyDateInstance.getTime());
        }
        followUpRecords.setMedicalRecordId(medicalRecordId);
        followUpRecords.setMedicalRecordName(request.getMedicalRecordName());
        followUpRecords.setOrganizationId(fusTeamChronicGroupRecord.getOrganizationId());
        followUpRecords.setDepartmentId(fusTeamChronicGroupRecord.getDepartmentId());
        followUpRecords.setDepartmentName(fusTeamChronicGroupRecord.getDepartmentName());
        followUpRecords.setDoctorId(fusTeamChronicGroupRecord.getDoctorId());
        followUpRecords.setDocId(fusTeamChronicGroupRecord.getDocId());
        followUpRecords.setDoctorName(fusTeamChronicGroupRecord.getDoctorName());
        followUpRecords.setPatientId(fusTeamChronicGroupRecord.getPatientId());
        followUpRecords.setCardType(fusTeamChronicGroupRecord.getCardType());
        followUpRecords.setCardNumber(fusTeamChronicGroupRecord.getCardNumber());
        followUpRecords.setPatientName(fusTeamChronicGroupRecord.getPersonName());
        followUpRecords.setPatientMedicalCardType(fusTeamChronicGroupRecord.getPatientMedicalCardType());
        followUpRecords.setPatientMedicalCardNumber(fusTeamChronicGroupRecord.getPatientMedicalCardNumber());
        followUpRecords.setPatientSex(fusTeamChronicGroupRecord.getPersonSex());
        followUpRecords.setPatientAge(fusTeamChronicGroupRecord.getAge() == null ? null :
                fusTeamChronicGroupRecord.getAge().intValue());
        followUpRecords.setTelephone(fusTeamChronicGroupRecord.getTelephone());
        followUpRecords.setCreateTime(now);
        followUpRecords.setTeamChronicGroupId(fusTeamChronicGroupRecord.getTeamChronicGroupId());
        followUpRecords.setMedicalTeamId(fusTeamChronicGroupRecord.getMedicalTeamId());
        followUpRecords.setMedicalTeamName(fusTeamChronicGroupRecord.getMedicalTeamName());
        followUpRecords.setGmtCreate(now);
        followUpRecords.setGmtModified(now);
        followUpRecords.setAbnormalReadFlag(Constants.ZORE_STRING);
        followUpRecords.setAnswerAbnormal(Constants.TWO_STRING);
        if (StringUtils.isEmpty(request.getAutoCreateFlag())) {
            request.setAutoCreateFlag(Constants.ZORE_STRING);
        }
        followUpRecords.setAutoCreateFlag(request.getAutoCreateFlag());
        followUpRecords.setAuditStatus((byte) 0);
        followUpRecordsDAO.save(followUpRecords);
/*
        FollowUpRecordsRequisition in = new FollowUpRecordsRequisition();
        in.setFormId(KeyGenerator.randomGenerate());
        in.setRecordId(followUpRecords.getRecordId());
        in.setCreateId(request.getOperatorId());
        in.setCreateDt(new Date());
        in.setModifyDt(new Date());
        in.setQuestionnaireId(medicalRecordId);
        in.setQuestionnaireName(medicalRecordName);

        followUpRecordsRequisitionDAO.insertSelective(in);*/
        //表单改成多选集合形式
        //保存表单

        List<FollowUpQuestionnaireDTO> qList = request.getQuestionnaireList();
        if (!CollectionUtils.isEmpty(qList)) {
            qList.forEach(q -> {
                FollowUpRecordsRequisition insert = new FollowUpRecordsRequisition();
                insert.setFormId(KeyGenerator.randomGenerate());
                insert.setRecordId(followUpRecords.getRecordId());
                insert.setCreateId(request.getOperatorId());
                insert.setExecuteId(request.getOperatorId());
                insert.setExecuteName("");
                insert.setCreateDt(new Date());
                insert.setModifyDt(new Date());
                insert.setQuestionnaireId(q.getQuestionnaireId());
                insert.setQuestionnaireName(q.getQuestionnaireName());
                insert.setUserInfoId("");
                followUpRecordsRequisitionDAO.insertSelective(insert);
            });
        }else if(StringUtils.isNotEmpty(request.getMedicalRecordId())){
            FollowUpRecordsRequisition insert = new FollowUpRecordsRequisition();
            insert.setFormId(KeyGenerator.randomGenerate());
            insert.setRecordId(followUpRecords.getRecordId());
            insert.setCreateId(request.getOperatorId());
            insert.setExecuteId(request.getOperatorId());
            insert.setExecuteName("");
            insert.setCreateDt(new Date());
            insert.setModifyDt(new Date());
            insert.setQuestionnaireId(request.getMedicalRecordId());
            insert.setQuestionnaireName(request.getMedicalRecordName());
            insert.setUserInfoId("");
            followUpRecordsRequisitionDAO.insertSelective(insert);
        }



        //保存健康宣教
        List<FollowUpRouteDetailForm> forms = request.getFollowUpRouteDetailForms();
        if (!CollectionUtils.isEmpty(forms)){
            forms.forEach(f->{
                if (f.getItemType()==3){
                    FollowUpRecordsEducation insert = new FollowUpRecordsEducation();
                    insert.setId(KeyGenerator.randomGenerate());
                    insert.setRecordId(followUpRecords.getRecordId());
                    insert.setEducationId(f.getEducationId());
                    insert.setEducationName(f.getEducationName());
                    insert.setDefaultPush(0);
                    insert.setCreateDt(new Date());
                    insert.setModifyDt(new Date());
                    followUpRecordsEducationDAO.insertSelective(insert);
                }
            });
        }

        if (!CollectionUtils.isEmpty(request.getFollowUpList())) {
            for (FollowUpRouteDetailContent content :
                    request.getFollowUpList()) {
                //todo 区别对待问卷随访和医护随访
                FollowUpRecordsContent insert = new FollowUpRecordsContent();
                insert.setIndexType(content.getIndexType());
                insert.setIndexClassifyId(content.getIndexClassifyId());
                insert.setIndexClassifyName(content.getIndexClassifyName());
                insert.setBusinessId(content.getBusinessId());
                insert.setBusinessName(content.getBusinessName());
                insert.setProjectDetails(content.getProjectDetails());
                insert.setFollowUpDetail(content.getFollowUpDetail());
                insert.setRecordId(followUpRecords.getRecordId());
                insert.setEducationStatus(Constants.ZORE_STRING);
                followUpRecordsContentDAO.save(insert);
            }
        }


        return followUpRecords;
    }

    /**
     * @param request
     * @throws
     * @description: 生成随访计划记录
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/7/21 14:19
     */
    @Override
    @RpcService
    public String produceExecutionList(ProduceExecutionListRequest request) throws ControllerException {
        StringBuilder messageBuilder = new StringBuilder();
        if (CommonUtils.isNull(request.getDiseaseTypeId())) {
            if (StringUtils.isAnyEmpty(request.getDocId(), request.getOperatorId())) {
                throw new ControllerException(ResultCode.ERROR, "入参不能为空");
            }

            GroupMemberRequest groupMemberRequest = new GroupMemberRequest();
            groupMemberRequest.setDocId(request.getDocId());
            List<ChronicTeamList> chronicTeamLists = docTeamRpcService.queryTeamList(groupMemberRequest);
            if(CommonUtils.isNotEmpty(chronicTeamLists)){
                List<Long> collect = chronicTeamLists.stream().map(c -> c.getMedicalTeamId()).collect(Collectors.toList());
                if(CommonUtils.isNotEmpty(collect)){
                    List<QueryChronicListResponse> list = fusTeamChronicGroupRecordDAO.queryChronicList(collect);
                    if (!CollectionUtils.isEmpty(list)) {
                        for (QueryChronicListResponse queryChronicListResponse :
                                list) {
                            produceExecutionListByDiseaseTypeId(queryChronicListResponse.getChronicDiseaseId(), messageBuilder,
                                    request.getOperatorId());
                        }
                    }
                }
            }


        } else {
            if (CommonUtils.isEmpty(request.getDiseaseTypeId()) || CommonUtils.isEmpty(request.getOperatorId())) {
                throw new ControllerException(ResultCode.ERROR, "入参不能为空");
            }
            produceExecutionListByDiseaseTypeId(request.getDiseaseTypeId(), messageBuilder, request.getOperatorId());
        }
        return messageBuilder.toString();
    }

    /**
     * @throws
     * @description: 自动终止随访计划
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/7/29 17:47
     */
    @Override
    @RpcService
    public String autoStopExecutionList() throws ControllerException {
        StringBuilder messageBuilder = new StringBuilder();
        Date now = new Date();
        //更新已经出组的随访执行计划
        final Integer updateCount = followUpRecordsDAO.updateByOutGroup(now, (byte) 0, (byte) 9, adminUserId, "3");
        logger.info("终止已出组的随访执行计划数量：{}", updateCount);
        messageBuilder.append("终止已出组的随访执行计划数量：").append(updateCount).append("\n");
        //查询出所有未结束的执行计划生产记录,进行处理
        handleUnFinishedProduceRecord(now);
        //先查询到所有未终止的随访生产记录对应的随访路径详情
        List<FollowUpRouteDetail> followUpRouteDetails = followUpRouteDetailDAO.queryUnFinishedForProduceRecord();
        //根据随访路径详情查询到对应的因素规则
        if (!CollectionUtils.isEmpty(followUpRouteDetails)) {
            for (FollowUpRouteDetail followUpRouteDetail :
                    followUpRouteDetails) {
                Long routeId = followUpRouteDetail.getRouteId();
                Long routeDetailId = followUpRouteDetail.getRouteDetailId();

                List<FollowUpRouteDetailFactor> followUpRouteDetailFactors =
                        followUpRouteDetailFactorDAO.queryByRouteDetailId(routeDetailId, FactorFlagEnum.STOP.getType());
                if (!CollectionUtils.isEmpty(followUpRouteDetailFactors)) {
                    FollowUpRoute followUpRoute = followUpRouteDAO.get(routeId);
                    if (followUpRoute == null) {
                        logger.info("RouteId:{},随访路径不存在，无法进行停止因素筛选", routeId);
                        messageBuilder.append("RouteId:{" + routeId + "},随访路径不存在，无法进行停止因素筛选").append("\n");
                        continue;
                    }

                    //遍历的所有因素依次执行筛选:
                    //and相连的因素检索出来的数据求交集，遇到OR连接符时，把前面检索出来的数据集合保存，
                    //后面检索出来的数据在遇到下一个OR连接符或者结束时与前面检索出来的数据集合求并集
                    List<String> previousList = new ArrayList<>();
                    //病人因素信息存储集合，key是病人id，value是按顺序存储的因素数据集合
                    Map<String, List<FactorData>> patientInfoMap = new HashMap<>(256);
                    //循环执行机制 0 不执行 1 执行
                    Byte isLoopExecute = followUpRouteDetail.getIsLoopExecute();
                    Long diseaseTypeId = followUpRoute.getDiseaseTypeId();
                    //处理因素列表得到人员信息集合和因素数据集合
                    followUpCommonService.handleFactorList(followUpRoute, isLoopExecute, followUpRouteDetailFactors,
                            previousList, patientInfoMap);

                    //去重
                    if (!CollectionUtils.isEmpty(previousList)) {
                        HashSet<String> h = new HashSet(previousList);
                        previousList.clear();
                        previousList.addAll(h);
                    }


                    List<FollowUpPlanProduceRecord> followUpPlanProduceRecords =
                            followUpPlanProduceRecordDAO.queryByPatientIdList(previousList, diseaseTypeId);
                    for (FollowUpPlanProduceRecord followUpPlanProduceRecord :
                            followUpPlanProduceRecords) {
                        //进行随访计划终止操作
                        stopPlanByFollowUpPlanProduceRecord(now, followUpPlanProduceRecord);
                    }
                } else {
                    logger.info("RouteId:{},RouteDetailId:{},随访路径详情没有停止因素，无法进行停止因素筛选", routeId, routeDetailId);
                    messageBuilder.append("RouteId:{" + routeId + "},RouteDetailId:{" + routeDetailId + "}," +
                            "随访路径详情没有停止因素，无法进行停止因素筛选").append("\n");
                }
            }
        }
        return messageBuilder.toString();
    }

    /**
     * @param messageBuilder
     * @param routeDetailId
     * @param diseaseTypeId
     * @param followUpPlanProduceRecordIdList
     * @param i
     * @param followUpRouteDetailFactor
     * @throws
     * @description:
     * @return: java.util.List<java.lang.Long>
     * @author: tongtp
     * @date: 2020/7/30 17:38
     */
    private List<Long> getIdsByFollowUpRouteDetailFactor(StringBuilder messageBuilder, Long routeDetailId,
                                                         Long diseaseTypeId,
                                                         List<Long> followUpPlanProduceRecordIdList, int i,
                                                         FollowUpRouteDetailFactorRelation followUpRouteDetailFactor, String factorId) {
        //因素类别,1关联手术 2关联疾病 3关联指标 4关联并发症 5路径节点
        List<Long> tempIdList = new ArrayList<>();
        String factorResultOne = followUpRouteDetailFactor.getFactorResultOne();
        factorId = factorId + "";
        switch (followUpRouteDetailFactor.getFactorType()) {
            //所有的因素检索都要按照病种检索
            case (byte) 1:
                //因素内容结果，关联手术、关联疾病和关联并发症，结果是1和0，关联指标的结果需要从关键指标结果中获取，路径节点结果值是1日 2周 3月
                QueryByOperativeRequest queryByOperativeRequest = new QueryByOperativeRequest();
                queryByOperativeRequest.setDiseaseTypeId(diseaseTypeId);
                queryByOperativeRequest.setOperativeCode(factorId);
                queryByOperativeRequest.setRouteDetailId(routeDetailId);
                if ("1".equals(factorResultOne)) {
                    tempIdList =
                            followUpPlanProduceRecordDAO.queryByOperativeAndYes(queryByOperativeRequest);
                } else {
                    tempIdList =
                            followUpPlanProduceRecordDAO.queryByOperativeAndNO(queryByOperativeRequest);
                }
                break;
            case (byte) 3:
                QueryByIndexRequest queryByIndexRequest = new QueryByIndexRequest();
                queryByIndexRequest.setDiseaseTypeId(diseaseTypeId);
                queryByIndexRequest.setFactorNatureType(followUpRouteDetailFactor.getFactorNatureType());
                queryByIndexRequest.setFactorResultOne(factorResultOne);
                queryByIndexRequest.setFactorResultTwo(followUpRouteDetailFactor.getFactorResultTwo());
                queryByIndexRequest.setFactorResultUnit(followUpRouteDetailFactor.getFactorResultUnit());
                queryByIndexRequest.setRouteDetailId(routeDetailId);
                queryByIndexRequest.setItemId(factorId);
                tempIdList = followUpPlanProduceRecordDAO.queryByIndex(queryByIndexRequest);
                break;
            case (byte) 2:
            case (byte) 4:
                //因素内容结果，关联手术、关联疾病和关联并发症，结果是1和0，关联指标的结果需要从关键指标结果中获取，路径节点结果值是1日 2周 3月
                QueryByDiagnosisRequest queryByDiagnosisRequest = new QueryByDiagnosisRequest();
                queryByDiagnosisRequest.setDiseaseTypeId(diseaseTypeId);
                queryByDiagnosisRequest.setDiagnosisId(factorId);
                queryByDiagnosisRequest.setRouteDetailId(routeDetailId);
                if ("1".equals(factorResultOne)) {
                    tempIdList =
                            followUpPlanProduceRecordDAO.queryByDiagnosisAndYes(queryByDiagnosisRequest);
                } else {
                    tempIdList =
                            followUpPlanProduceRecordDAO.queryByDiagnosisAndNO(queryByDiagnosisRequest);
                }
                break;
            case (byte) 5: {
                //根据路径节点时间得到id集合
                tempIdList = getIdsByRouteNodeTime(messageBuilder, routeDetailId, diseaseTypeId,
                        followUpRouteDetailFactor, tempIdList, factorResultOne, factorId);
                break;
            }
            default:
                break;
        }
        if (i == 0) {
            followUpPlanProduceRecordIdList = tempIdList;
        } else {
            followUpPlanProduceRecordIdList.retainAll(tempIdList);
        }
        if (CollectionUtils.isEmpty(followUpPlanProduceRecordIdList)) {
            return null;
        }
        return followUpPlanProduceRecordIdList;
    }

    /**
     * @param messageBuilder
     * @param routeDetailId
     * @param diseaseTypeId
     * @param followUpRouteDetailFactor
     * @param tempIdList
     * @param factorResultOne
     * @param factorId
     * @throws
     * @description: 根据路径节点时间得到id集合
     * @return: java.util.List<java.lang.Long>
     * @author: tongtp
     * @date: 2020/7/30 17:42
     */
    private List<Long> getIdsByRouteNodeTime(StringBuilder messageBuilder, Long routeDetailId, Long diseaseTypeId,
                                             FollowUpRouteDetailFactorRelation followUpRouteDetailFactor,
                                             List<Long> tempIdList, String factorResultOne, String factorId) {
        //时间间隔-天数
        Integer timeInterval;
        //时间节点长度单位，1日 2周 3月
        String factorResultUnit = followUpRouteDetailFactor.getFactorResultUnit();
        Integer factorNumber;
        try {
            factorNumber = Integer.valueOf(factorResultOne);
        } catch (Exception e) {
            logger.info("RouteDetailFactorId:{},factorResultOne:{}转化成数值失败:{}",
                    followUpRouteDetailFactor.getRouteDetailFactorId(),
                    factorResultOne, e.getMessage());
            messageBuilder.append("RouteDetailFactorId:{" + followUpRouteDetailFactor.getRouteDetailFactorId() + "}," +
                    "factorResultOne:{" +
                    factorResultOne + "}转化成数值失败").append("\n");
            factorNumber = null;
        }
        if (factorNumber != null) {
            switch (factorResultUnit) {
                case "1":
                    timeInterval = factorNumber;
                    break;
                case "2":
                    timeInterval = factorNumber * 7;
                    break;
                case "3":
                    timeInterval = factorNumber * 30;
                    break;
                default:
                    timeInterval = null;
                    break;
            }
            if (timeInterval != null) {
                Calendar instance = Calendar.getInstance();
                instance.add(Calendar.DAY_OF_YEAR, -timeInterval);
                //发生事件时间点
                Date happenTime = instance.getTime();
                //根据事件节点得到id集合
                tempIdList = getIdsByHappenTime(routeDetailId, diseaseTypeId, tempIdList, factorId, happenTime);
            } else {
                logger.info("factorNumber:{},factorResultUnit:{}计算时间间隔天数失败",
                        factorNumber, factorResultUnit);
                messageBuilder.append("factorNumber:{" + factorNumber + "},factorResultUnit:{" + factorResultUnit +
                        "}计算时间间隔天数失败").append("\n");
            }
        }
        return tempIdList;
    }

    /**
     * @param routeDetailId
     * @param diseaseTypeId
     * @param tempIdList
     * @param factorId
     * @param happenTime
     * @throws
     * @description: 根据事件节点得到id集合
     * @return: java.util.List<java.lang.Long>
     * @author: tongtp
     * @date: 2020/7/30 17:44
     */
    private List<Long> getIdsByHappenTime(Long routeDetailId, Long diseaseTypeId, List<Long> tempIdList,
                                          String factorId, Date happenTime) {
        //时间类型：1入组 2术后 3出院 4门诊
        switch (factorId) {
            case "1":
                QueryByHappenTimeRequest queryByHappenTimeRequest =
                        new QueryByHappenTimeRequest();
                queryByHappenTimeRequest.setHappenTime(happenTime);
                queryByHappenTimeRequest.setRouteDetailId(routeDetailId);
                queryByHappenTimeRequest.setDiseaseTypeId(diseaseTypeId);
                tempIdList =
                        followUpPlanProduceRecordDAO.queryByHappenTime(queryByHappenTimeRequest);
                break;
            case "2":
                //查询这个病种相关的手术最近一次手术
            case "3":
                //查询这个病种最近一次住院的出院时间
            case "4":
                //查询这个病种最近一次门诊
                List<FollowUpPlanProduceRecord> tempFollowUpPlanProduceRecords =
                        followUpPlanProduceRecordDAO.queryByUnFinished();
                if (CollectionUtils.isEmpty(tempFollowUpPlanProduceRecords)) {
                    Date tempDate;
                    for (FollowUpPlanProduceRecord followUpPlanProduceRecord :
                            tempFollowUpPlanProduceRecords) {
                        FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord =
                                fusTeamChronicGroupRecordDAO.get(followUpPlanProduceRecord.getTeamChronicGroupId());
                        switch (factorId) {
                            case "2":
                                //查询这个病种相关的手术最近一次手术
                                QueryOperativeTimeRequest queryOperativeTimeRequest =
                                        new QueryOperativeTimeRequest();
                                queryOperativeTimeRequest.setDiseaseTypeId
                                        (diseaseTypeId);
                                queryOperativeTimeRequest.setPatientId
                                        (fusTeamChronicGroupRecord.getPersonId());
                                queryOperativeTimeRequest.setCardType
                                        (fusTeamChronicGroupRecord.getCardType());
                                queryOperativeTimeRequest.setCardNumber
                                        (fusTeamChronicGroupRecord.getCardNumber());
                                tempDate =
                                        produceExecutionListDAO.queryOperativeTime(queryOperativeTimeRequest);
                                break;
                            case "3":
                                //查询这个病种最近一次住院的出院时间
                                QueryDischargeTimeRequest queryDischargeTimeRequest =
                                        new QueryDischargeTimeRequest();
                                queryDischargeTimeRequest.setDiseaseTypeId(diseaseTypeId);
                                queryDischargeTimeRequest.setPatientId
                                        (fusTeamChronicGroupRecord.getPersonId());
                                queryDischargeTimeRequest.setCardType
                                        (fusTeamChronicGroupRecord.getCardType());
                                queryDischargeTimeRequest.setCardNumber
                                        (fusTeamChronicGroupRecord.getCardNumber());
                                tempDate =
                                        produceExecutionListDAO.queryDischargeTime(queryDischargeTimeRequest);
                                break;
                            case "4":
                                //查询这个病种最近一次门诊
                                QueryVisitTimeRequest queryVisitTimeRequest =
                                        new QueryVisitTimeRequest();
                                queryVisitTimeRequest.setDiseaseTypeId(diseaseTypeId);
                                queryVisitTimeRequest.setPatientId
                                        (fusTeamChronicGroupRecord.getPersonId());
                                queryVisitTimeRequest.setCardType
                                        (fusTeamChronicGroupRecord.getCardType());
                                queryVisitTimeRequest.setCardNumber
                                        (fusTeamChronicGroupRecord.getCardNumber());
                                tempDate =
                                        produceExecutionListDAO.queryVisitTime(queryVisitTimeRequest);
                                break;
                            default:
                                tempDate = null;
                                break;
                        }
                        if (tempDate != null && happenTime.after(tempDate)) {
                            tempIdList.add(followUpPlanProduceRecord.getId());
                        }
                    }
                }
            default:
                break;
        }
        return tempIdList;
    }

    /**
     * @param now
     * @throws
     * @description: 查询出所有未结束的执行计划生产记录, 进行处理
     * @return: void
     * @author: tongtp
     * @date: 2020/7/30 14:11
     */
    private void handleUnFinishedProduceRecord(Date now) {
        List<FollowUpPlanProduceRecord> followUpPlanProduceRecords = followUpPlanProduceRecordDAO.queryByUnFinished();
        if (!CollectionUtils.isEmpty(followUpPlanProduceRecords)) {
            for (FollowUpPlanProduceRecord followUpPlanProduceRecord :
                    followUpPlanProduceRecords) {
                //查询是否存在计划时间大于当前时间的未随访的随访计划
                //随访状态：0未随访 1 已随访 9 已终止
                Long count = followUpRecordsDAO.getCountByPlanTimeAndStatus(now, (byte) 0,
                        followUpPlanProduceRecord.getTeamChronicGroupId(),
                        followUpPlanProduceRecord.getRouteDetailId());
                if (count == null || count < 1L) {
                    endFollowUpPlanProduceRecord(now, followUpPlanProduceRecord);
                } else {
                    //存在计划时间大于当前时间的未随访的随访计划
                    //查询该条出组记录是否已出组
                    FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecordEntity =
                            fusTeamChronicGroupRecordDAO.get(followUpPlanProduceRecord.getTeamChronicGroupId());
                    //0待入组（待审核）  1已入组（审核通过） 2入组失败（审核失败） 3已出组
                    if ("3".equals(fusTeamChronicGroupRecordEntity.getApplyStatus())) {
                        //已出组的进行随访计划终止操作
                        stopPlanByFollowUpPlanProduceRecord(now, followUpPlanProduceRecord);
                    }
                }
            }
        }
    }

    /**
     * @param now
     * @param followUpPlanProduceRecord
     * @throws
     * @description: 进行随访计划终止操作
     * @return: void
     * @author: tongtp
     * @date: 2020/7/30 14:04
     */
    private void stopPlanByFollowUpPlanProduceRecord(Date now, FollowUpPlanProduceRecord followUpPlanProduceRecord) {
        //先终止随访执行计划列表
        //随访状态：0未随访 1 已随访 9 已终止
        logger.info("满足停止因素进行随访计划终止now:{},TeamChronicGroupId:{},RouteDetailId:{}", now,
                followUpPlanProduceRecord.getTeamChronicGroupId(),
                followUpPlanProduceRecord.getRouteDetailId());
        followUpRecordsDAO.updateByPlanTimeAndStatus(now, (byte) 0,
                followUpPlanProduceRecord.getTeamChronicGroupId(),
                followUpPlanProduceRecord.getRouteDetailId(), (byte) 9, adminUserId);
        //然后更新随访计划生产记录表
        endFollowUpPlanProduceRecord(now, followUpPlanProduceRecord);
    }

    /**
     * @param now
     * @param followUpPlanProduceRecord
     * @throws
     * @description: 更新随访计划生产记录表
     * @return: void
     * @author: tongtp
     * @date: 2020/7/30 13:36
     */
    private void endFollowUpPlanProduceRecord(Date now, FollowUpPlanProduceRecord followUpPlanProduceRecord) {
        followUpPlanProduceRecord.setGmtModified(now);
        //状态：1 开始 2 结束（随访频率临时的直接结束）
        followUpPlanProduceRecord.setStatus((byte) 2);
        followUpPlanProduceRecordDAO.update(followUpPlanProduceRecord);
    }

    /**
     * @throws
     * @description: 生成所有随访计划记录
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/7/21 14:31
     */
    @Override
    @RpcService
    public void produceExecutionListAll() throws ControllerException {
        //查询所有启用的随访路径
        List<FollowUpRoute> followUpRoutes =
                followUpRouteDAO.queryByFollowTypeAndStatus(FollowTypeEnum.FUS_SPECIALIST.getType(),
                        FollowUpRouteStatusEnum.ENABLE.getStatus());
        if (!CollectionUtils.isEmpty(followUpRoutes)) {
            for (FollowUpRoute followUpRoute :
                    followUpRoutes) {
                doProduceExecutionList(followUpRoute, adminUserId);
            }
        }
        return;
    }

    /**
     * @param request
     * @throws
     * @description: 获取随访计划记录
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/7/21 14:19
     */
    @Override
    @RpcService
    public QueryExecutionListResponse queryExecutionList(QueryExecutionListRequest request) throws ControllerException {
        QueryExecutionListResponse response = new QueryExecutionListResponse();
        /**
         * 这里需要通过医生的id查询到医生的所有所属团队,当是专科随访且pc端设置成了团队共享需要查询到团队内所有的随访信息,否则不显示
         * 这里要考虑到管理员的情况,思路是先查询到医生拥有的所有的团队id,然后在团队表中查,共享状态为为共享的专科随访
         */
        List<Long> medicalTeamIdsByDoctorId = null;
        //传值医生id不为空保证是查询医生的专科随访 非空判断要求是医生查询而不是管理员查询
        List<Long> teamIdList = null;
        List<String> chronicDiseaseId = null;
        List<FollowUpRecordsVO> followUpRecords = null;
        Long teamIdCount = 0L;
        if (CommonUtils.isNotEmpty(request.getDocId())) {
            medicalTeamIdsByDoctorId = docTeamMemberRpcService.findMedicalTeamIdsByDoctorId(request.getDocId());
            if (CommonUtils.isNotEmpty(request.getDocId())) {
                if (CommonUtils.isEmpty(medicalTeamIdsByDoctorId)) {
                    return response;
                }
                //这里筛选团队必须是专科随访团队
                teamIdList = docTeamRpcService.queryMedicalTeamId(medicalTeamIdsByDoctorId);
                if (CommonUtils.isNotEmpty(teamIdList)){
                    //查询该医生拥有的团队下管理的所有病种
                    chronicDiseaseId = docTeamDiseaseDAO.findChronicDiseaseId(teamIdList);
                }
                request.setMedicalTeamId(teamIdList);
            }
            if (CommonUtils.isNotEmpty(chronicDiseaseId)){
                boolean contains = false;
                if (CommonUtils.isNotEmpty(request.getDiseaseTypeId())){
                    contains = chronicDiseaseId.contains(String.valueOf(request.getDiseaseTypeId()));
                    if (contains){
                        request.setDocId(null);
                        //该医生管理的病种中包含这个查询的病种时则查询这个病种的所有随访记录否则查询全部的
                        //查询该医生拥有查看病种的权限
                        teamIdCount = followUpRecordsDAO.queryExecutionListByTeamIdCount(request);
                        //查询到专科随访开启团队共享不含本医生的随访计划加上这个医生的随访计划等于总随访计划
                        followUpRecords = followUpRecordsDAO.queryExecutionListByTeamId(request);
                    }else {
                        return response;
                    }
                }else {
                    //未传病种id就要查询这个医生可以查看的所有的病种.传了病种id要判断这个医生是否有病种的查看权限
                    request.setDocId(null);
                    request.setTeamChronicDiseaseIdList(chronicDiseaseId);
                    //查询该医生拥有查看病种的权限
                    teamIdCount = followUpRecordsDAO.queryExecutionListByTeamIdCount(request);
                    //查询到专科随访开启团队共享不含本医生的随访计划加上这个医生的随访计划等于总随访计划
                    followUpRecords = followUpRecordsDAO.queryExecutionListByTeamId(request);
                }
            }else {
                return response;
            }
        }else {
            teamIdCount = followUpRecordsDAO.queryExecutionListByTeamIdCount(request);
            followUpRecords = followUpRecordsDAO.queryExecutionListByTeamId(request);
        }
        response.setTotal(teamIdCount);
        if (!CollectionUtils.isEmpty(followUpRecords)) {
//			在这个时间之后执行的可以修改
            Date canUpdateTime = getCanUpdateTime(request.getOrganizationId());
            //查询随访内容
            List<Long> recordIds = new ArrayList<>();
            for (FollowUpRecords followUpRecord :
                    followUpRecords) {
                recordIds.add(followUpRecord.getRecordId());
            }
            List<FollowUpRecordsContent> followUpRecordsContents =
                    followUpRecordsContentDAO.queryByRecordIds(recordIds);
            for (FollowUpRecordsVO followUpRecord : followUpRecords) {
                if (followUpRecord.getExecuteTime() != null) {
                    //是否允许修改 0 不允许 1 允许
                    if (followUpRecord.getExecuteTime().after(canUpdateTime)) {
                        followUpRecord.setCanUpdate(1);
                    } else {
                        followUpRecord.setCanUpdate(0);
                    }
                } else {
                    followUpRecord.setCanUpdate(0);
                }
                List<FollowUpRecordsContent> contentList = new ArrayList<>();
                Long recordId = followUpRecord.getRecordId();
                if (!CollectionUtils.isEmpty(followUpRecordsContents)) {
                    for (int i = 0; i < followUpRecordsContents.size(); ) {
                        if (recordId.equals(followUpRecordsContents.get(i).getRecordId())) {
                            contentList.add(followUpRecordsContents.remove(i));
                        } else {
                            i++;
                        }
                    }
                }

                FollowUpRecordsEducation eQuery = new FollowUpRecordsEducation();
                eQuery.setRecordId(recordId);
                List<FollowUpRecordsEducation> followUpRecordsEducations = followUpRecordsEducationDAO.selectList(eQuery);

                //宣教
                if (!CollectionUtils.isEmpty(followUpRecordsEducations)) {
                    List<FollowUpEducationVO> collect = followUpRecordsEducations.stream().map(f -> {
                        FollowUpEducationVO dto = new FollowUpEducationVO();
                        dto.setId(f.getId());
                        dto.setEducationId(f.getEducationId());
                        dto.setEducationName(f.getEducationName());
                        dto.setEducationStatus(f.getEducationStatus());
                        return dto;

                    }).collect(Collectors.toList());
                    followUpRecord.setEducationList(collect);
                }

                //表单
                FollowUpRecordsRequisition fQuery = new FollowUpRecordsRequisition();
                fQuery.setRecordId(recordId);
                List<FollowUpRecordsRequisition> requisitions = followUpRecordsRequisitionDAO.selectList(fQuery);
                if (!CollectionUtils.isEmpty(requisitions)) {
                    List<FollowUpQuestionnaireDTO> collect1 = requisitions.stream().map(f -> {
                        FollowUpQuestionnaireDTO dto = new FollowUpQuestionnaireDTO();
                        dto.setFormId(f.getFormId());
                        dto.setQuestionnaireId(f.getQuestionnaireId());
                        dto.setQuestionnaireName(f.getQuestionnaireName());
                        dto.setUserInfoId(f.getUserInfoId());
                        return dto;
                    }).collect(Collectors.toList());
                    followUpRecord.setQuestionnaireList(collect1);
                }

                followUpRecord.setContentList(contentList);

                //获取机构名称
                Organization organization = organizationRpcService.getOrgDetailByOrgCode(followUpRecord.getOrganizationId());
                if (organization != null) {
                    followUpRecord.setOrganizationName(organization.getFullName());
                }

            }
            response.setList(followUpRecords);
        }
        return response;
    }

    /**
     * 获取随访计划详情
     *
     * @param request 随访id
     * @return 随访详情
     */
    @Override
    @RpcService
    public FollowUpRecordsVO queryFollowUpDetail(QueryDoctorFollowupReq request) {
        FollowUpRecordsVO followUpRecordsVO = new FollowUpRecordsVO();
        FollowUpRecords followUpRecords = followUpRecordsDAO.getFollowUpDetailById(request.getRecordId());
        if (followUpRecords == null) {
            return followUpRecordsVO;
        }
        Long recordId = followUpRecords.getRecordId();
        //获取随访表单列表

        FollowUpRecordsRequisition query = new FollowUpRecordsRequisition();
        query.setRecordId(recordId);
        List<FollowUpRecordsRequisition> requisitions = followUpRecordsRequisitionDAO.selectList(query);
        if (!CollectionUtils.isEmpty(requisitions)) {
            List<FollowUpQuestionnaireDTO> questionnaireList = requisitions.stream().map(r -> {
                FollowUpQuestionnaireDTO f = new FollowUpQuestionnaireDTO();
                f.setFormId(r.getFormId());
                f.setQuestionnaireId(r.getQuestionnaireId());
                if(StringUtils.isNotEmpty(r.getQuestionnaireName())){
                    f.setQuestionnaireName(HTMLSpirit.delHTMLTag(r.getQuestionnaireName()));
                }
                f.setUserInfoId(r.getUserInfoId());
                return f;
            }).collect(Collectors.toList());
            followUpRecordsVO.setQuestionnaireList(questionnaireList);
        }

        //获取健康宣教
        FollowUpRecordsEducation q2 = new FollowUpRecordsEducation();
        q2.setRecordId(recordId);
        List<FollowUpRecordsEducation> educations = followUpRecordsEducationDAO.selectList(q2);
        if (!CollectionUtils.isEmpty(educations)) {
            List<FollowUpEducationVO> educationList = educations.stream().map(e -> {
                Long educationId = e.getEducationId();
                FusHealthEducationEntity f = fusHealthEducationDAO.get(educationId);
                FollowUpEducationVO education = new FollowUpEducationVO();
                education.setId(e.getId());
                education.setEducationId(e.getEducationId());
                education.setEducationName(e.getEducationName());
                if (Objects.nonNull(f)) {
                    education.setContent(f.getContent());
                }

                return education;
            }).collect(Collectors.toList());
            followUpRecordsVO.setEducationList(educationList);
        }

        BeanUtils.copyProperties(followUpRecords, followUpRecordsVO);
        Date canUpdateTime = getCanUpdateTime(followUpRecordsVO.getOrganizationId());

        List<FollowUpRecordsContent> followUpRecordsContents = followUpRecordsContentDAO.queryContentByRecordId(request.getRecordId());
        if (followUpRecordsVO.getExecuteTime() != null) {
            //是否允许修改 0 不允许 1 允许
            if (followUpRecordsVO.getExecuteTime().after(canUpdateTime)) {
                followUpRecordsVO.setCanUpdate(1);
            } else {
                followUpRecordsVO.setCanUpdate(0);
            }
        } else {
            followUpRecordsVO.setCanUpdate(0);
        }
        //获取机构名称
        Organization organization = organizationRpcService.getOrgDetailByOrgCode(followUpRecordsVO.getOrganizationId());
        if (organization != null) {
            followUpRecordsVO.setOrganizationName(organization.getFullName());
        }
        List<FollowUpRecordsContent> contentList = Lists.newArrayList();
        followUpRecordsVO.setContentList(contentList);
        if (CollectionUtils.isEmpty(followUpRecordsContents)) {
            return followUpRecordsVO;
        }
        for (int i = 0; i < followUpRecordsContents.size(); ) {
            if (followUpRecordsVO.getRecordId().equals(followUpRecordsContents.get(i).getRecordId())) {
                contentList.add(followUpRecordsContents.remove(i));
            } else {
                i++;
            }
        }

        //查询person
        if (!StringUtils.isEmpty(followUpRecordsVO.getCardNumber()) && !StringUtils.isEmpty(followUpRecordsVO.getCardType())) {
            //查询personId
            Certificate cert = new Certificate(followUpRecordsVO.getCardType(), followUpRecordsVO.getCardNumber(), "01");
            try {
                Person person = mpiProvider.getPersonByCertificate(cert);
                if (Objects.nonNull(person)) {
                    followUpRecordsVO.setPersonId(person.getMpiId());
                }
            } catch (MPIException e) {
                logger.error("获取用户信息失败");
            }
        }
        return followUpRecordsVO;
    }

    /**
     * 随访计划设置-医生站嵌入查询
     *
     * @param request
     */
    @Override
    @RpcService
    public FollowUpPathRouteDTO queryFollowUpPathSetting(QueryFollowUpPathRouteRequest request) throws ControllerException {
        if (CommonUtils.isNull(request.getOrganizationId()) || StringUtils.isEmpty(request.getVisitNo()) || request.getSource() == null) {
            throw new ControllerException(ResultCode.ERROR, "不能获取机构代码或者卡号或者门诊类别");
        }
        //frank
        //根据机构代码+就诊号+就诊类别查询是否存在数据
        FollowUpPathRouteDTO followUpPathRouteDTO = new FollowUpPathRouteDTO();
        FollowUpPathRouteEntity followUpPathRoute =
                followUpPathRouteDAO.getFuprByCardNoAndSource(request.getOrganizationId(), request.getVisitNo(),
                        request.getSource());
        if (followUpPathRoute != null) {
            BeanUtil.copyProperties(followUpPathRoute, followUpPathRouteDTO);
            List<FollowPatientLabelEntity> followPatientLabelEntities =
                    followPatientLabelDAO.findFplByFusPathRouteId(followUpPathRoute.getFusPathRouteId());
            followUpPathRouteDTO.setFollowPatientLabelEntities(followPatientLabelEntities);
            List<FollowPlanEntity> followPlanEntities =
                    followPlanDAO.findFplByFusPathRouteId(followUpPathRoute.getFusPathRouteId());
            List<FollowPlanDTO> followPlandtos = new ArrayList();
            if (CommonUtils.isNotEmpty(followPlanEntities)) {
                for (FollowPlanEntity followPlan : followPlanEntities) {
                    FollowPlanDTO dto = new FollowPlanDTO();
                    BeanUtil.copyProperties(followPlan, dto);
                    List<FollowUpPathRouteExplandEntity> follow =
                            followUpPathRouteExplandDAO.findFupreByFollowPlanId(followPlan.getFollowPlanId());
                    dto.setFollowUpPathRouteExplandEntityList(follow);
                    followPlandtos.add(dto);
                }
            }
//                大类添加计划list
            followUpPathRouteDTO.setFollowPlanEntities(followPlandtos);
        }
        return followUpPathRouteDTO;
    }

    /**
     * 随访计划设置-医生站嵌入-保存
     *
     * @param request
     */
    @Override
    public void saveFollowUpPathSetting(SaveFollowUpPathRouteRequest request) throws ControllerException {
        if (CommonUtils.isNull(request.getOrganizationId()) || StringUtils.isEmpty(request.getVisitNo()) || request.getSource() == null) {
            throw new ControllerException(ResultCode.ERROR, "不能获取机构代码或者卡号或者门诊类别");
        }
        String tenantId = RpcUserToken.getTenantId();
        FollowUpPathRouteDTO fupr = new FollowUpPathRouteDTO();
        BeanUtil.copyProperties(request, fupr);

        //查询随访设置主表
        FollowUpPathRouteEntity followUpPathRoute =
                followUpPathRouteDAO.getFuprByCardNoAndSource(request.getOrganizationId(), request.getVisitNo(),
                        request.getSource());

        FollowUpPathRouteEntity follow = new FollowUpPathRouteEntity();
        BeanUtil.copyProperties(fupr, follow);
        if (followUpPathRoute != null) {//更新
//            status =1的时候不允许更改,0 未生成随访计划 1 已生成随访计划
            if ((FollowPlanEnum.NOT_GENERATED.getType()).equals(followUpPathRoute.getStatus())) {
                Long fusPathRouteId = followUpPathRoute.getFusPathRouteId();
                //更新 follow_up_path_route
                follow.setFusPathRouteId(fusPathRouteId);
                follow.setCreateDt(followUpPathRoute.getCreateDt());
                follow.setModifiedDt(new Date());
//                followUpPathRouteDAO.updateSelective(follow);
                followUpPathRouteDAO.updateByFusPathRouteId(follow);
                //先删除在插入 follow_patient_label 患者标签
                followPatientLabelDAO.deleteFollowPatientLabelById(fusPathRouteId);
                if (fupr.getFollowPatientLabelEntities() != null) {
                    for (FollowPatientLabelEntity fplEntity : fupr.getFollowPatientLabelEntities()) {
                        fplEntity.setFusPathRouteId(fusPathRouteId);
                        fplEntity.setOrganizationId(fupr.getOrganizationId());
                        fplEntity.setVisitNo(fupr.getVisitNo());
                        fplEntity.setSource(fupr.getSource().intValue());
                        fplEntity.setTenantId(tenantId);
//                        followPatientLabelDAO.insert(fplEntity);
                        followPatientLabelDAO.save(fplEntity);
                    }
                }
                //先删除在插入 follow_plan 随访设置计划
                followPlanDAO.deleteFollowPlanById(fusPathRouteId);
                //先删除在插入 follow_up_path_route_expland 院后随访计划表单和宣教
                followUpPathRouteExplandDAO.deleteFollowPlanByFprId(fusPathRouteId);
                if (fupr.getFollowPlanEntities() != null) {
                    for (FollowPlanDTO dto : fupr.getFollowPlanEntities()) {
                        FollowPlanEntity entity = new FollowPlanEntity();
                        BeanUtil.copyProperties(dto, entity);
                        entity.setFusPathRouteId(fusPathRouteId);
                        entity.setCreateDt(new Date());
                        entity.setModifiedDt(new Date());
//                followPlanDAO.insert(entity);
                        FollowPlanEntity savePlan = followPlanDAO.save(entity);
                        Long followPlanId = savePlan.getFollowPlanId();

                        for (FollowUpPathRouteExplandEntity fEntity : dto.getFollowUpPathRouteExplandEntityList()) {
                            fEntity.setFusPathRouteId(fusPathRouteId);
                            fEntity.setFollowPlanId(followPlanId);
                            followUpPathRouteExplandDAO.insert(fEntity);
                        }
                    }
                }
            } else {
                throw new ControllerException("随访计划已生成不能更新");
            }
        } else {//插入
            //插入 follow_up_path_route
            follow.setTenantId(tenantId);
            follow.setCreateDt(new Date());
            follow.setModifiedDt(new Date());
            follow.setStatus(FollowPlanEnum.NOT_GENERATED.getType());
            FollowUpPathRouteEntity save = followUpPathRouteDAO.save(follow);
            Long fusPathRouteId = save.getFusPathRouteId();

            if (fupr.getFollowPatientLabelEntities() != null) {
                //插入 follow_patient_label
                for (FollowPatientLabelEntity fplEntity : fupr.getFollowPatientLabelEntities()) {
                    fplEntity.setFusPathRouteId(fusPathRouteId);
                    fplEntity.setOrganizationId(fupr.getOrganizationId());
                    fplEntity.setVisitNo(fupr.getVisitNo());
                    fplEntity.setSource(fupr.getSource().intValue());
                    fplEntity.setTenantId(tenantId);
//                        followPatientLabelDAO.insert(fplEntity);
                    followPatientLabelDAO.save(fplEntity);
                }
            }
            if (fupr.getFollowPlanEntities() != null) {
                for (FollowPlanDTO dto : fupr.getFollowPlanEntities()) {
                    FollowPlanEntity entity = new FollowPlanEntity();
                    BeanUtil.copyProperties(dto, entity);
                    //插入 follow_plan 随访设置计划
                    entity.setFusPathRouteId(fusPathRouteId);
                    entity.setRouteDetailType(dto.getRouteDetailType()==null?5:dto.getRouteDetailType().intValue());
                    entity.setCreateDt(new Date());
                    entity.setModifiedDt(new Date());
                    FollowPlanEntity savePlan = followPlanDAO.save(entity);
                    Long followPlanId = savePlan.getFollowPlanId();

                    for (FollowUpPathRouteExplandEntity fEntity : dto.getFollowUpPathRouteExplandEntityList()) {
                        //插入 follow_up_path_route_expland 院后随访计划表单和宣教
                        fEntity.setFusPathRouteId(fusPathRouteId);
                        fEntity.setFollowPlanId(followPlanId);
                        followUpPathRouteExplandDAO.save(fEntity);
                    }
                }
            }
        }

    }

    /**
     * @param organizationId
     * @throws
     * @description: 获取允许修改时间点
     * @return: java.util.Date
     * @author: tongtp
     * @date: 2020/8/17 10:17
     */
    private Date getCanUpdateTime(String organizationId) {
        //系统参数-随访结果提交后允许修改时间范围
        SysParameterRequest sysParameterRequest = new SysParameterRequest();
        sysParameterRequest.setType(projectSource);
        List<String> parameterKeyList = new ArrayList<>();
        if (InterfaceTypeEnum.HOL.getCode().equals(projectSource)) { //互联网医院
            parameterKeyList.add("FU_revise_time");
            sysParameterRequest.setOrganizationId(organizationId);
        } else if (InterfaceTypeEnum.GOL.getCode().equals(projectSource)) {//智慧健康通
            //租户级
            parameterKeyList.add("013101");
        }
        sysParameterRequest.setParameterKeyList(parameterKeyList);
        BaseResponse<List<ParameterResponse>> baseResponse =
                commonService.getSysParameterList(sysParameterRequest);
        //			允许修改时间间隔-天数，默认7天
        int canUpdateDays = 7;
        if (ResultCode.SUCCESS == baseResponse.getCode() && !CollectionUtils.isEmpty(baseResponse.getData())) {
            ParameterResponse parameterResponse = baseResponse.getData().get(0);
            if (parameterResponse.getParameterValue() != null) {
                try {
                    canUpdateDays = Integer.valueOf(parameterResponse.getParameterValue());
                } catch (Exception e) {
                    logger.info("FU_revise_time系统参数值为：{}，转换整型失败", parameterResponse.getParameterValue());
                }
            }
        }
        Calendar instance = Calendar.getInstance();
        instance.add(Calendar.DAY_OF_YEAR, -canUpdateDays);
        //在这个时间之后执行的可以修改
        return instance.getTime();
    }

    /**
     * @param request
     * @throws
     * @description: 保存随访结果
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/7/21 14:19
     */
    @Override
    @RpcService
    @UserEventTracking(type1 = CollectionInfoTypeEnum.USE_INFO, group1 = {CollectionInfoIdTypeEnum.CASE_HISTORY_INFO})
    public void saveFollowUpResult(SaveFollowUpResultRequest request) throws ControllerException {
        logger.info("saveFollowUpResult.request:{}", JSON.toJSONString(request));
        FollowUpRecords followUpRecords = followUpRecordsDAO.get(request.getRecordId());
        if (followUpRecords == null) {
            throw new ControllerException("随访执行计划不存在");
        }

        //2021年11月29日16:54:06 定世都强烈要求随访计划执行成功时可以没有随访问卷答案，鄙人反抗无果，含泪注释
//        if (StringUtils.isNotEmpty(followUpRecords.getMedicalRecordId()) && CommonUtils.isNull(request.getUserInfoId()) && "1".equals(request.getResultCode().toString())) {
//            //执行结果失败的时候可以不用传答案id
//            throw new ControllerException("问卷传入参数不能为空");
//        }
        if (Objects.equals(followUpRecords.getFollowUpStatus(), (byte) 1)) {
            //在这个时间之后执行的可以修改
            Date canUpdateTime = getCanUpdateTime(request.getOrganizationId());
            if (followUpRecords.getExecuteTime() != null && canUpdateTime.after(followUpRecords.getExecuteTime())) {
                throw new ControllerException("随访执行计划已经被执行,且过了可以修改时间，请刷新");
            }
        }
        if (CommonUtils.isNotNull(request.getUserInfoId())) {
            //进行重复的userInfoId校验
            FollowUpRecords tempFollowUpRecords =
                    followUpRecordsDAO.getByUserInfoId(request.getUserInfoId());
            if (tempFollowUpRecords != null && !tempFollowUpRecords.getRecordId().equals(followUpRecords.getRecordId())) {
                throw new ControllerException("问卷填写答案唯一标识userInfoId与已有数据重复");
            }
        }
        followUpRecords.setResultCode(request.getResultCode());
        followUpRecords.setResultCodeDetail(request.getResultCodeDetail());
        followUpRecords.setFollowUpStatus(request.getFollowUpStatus());
        followUpRecords.setExecuteId(request.getOperatorId());
        Date now = new Date();
        followUpRecords.setExecuteTime(now);
        followUpRecords.setGmtModified(now);
        followUpRecords.setUserInfoId(request.getUserInfoId());
        followUpRecords.setExecuteName(request.getOperatorName());
        if (StringUtils.isNotEmpty(request.getAnswerAbnormal())) {
            followUpRecords.setAnswerAbnormal(request.getAnswerAbnormal());
        }
        if (CommonUtils.isNotNull(request.getMedicalRecordUploadFlag())) {
            followUpRecords.setMedicalRecordUploadFlag(request.getMedicalRecordUploadFlag());
        }
        followUpRecordsDAO.update(followUpRecords);


        if (CommonUtils.isNotEmpty(request.getQuestionnaireId())) {
            List<FollowUpRecordsRequisition> followUpRecordsRequisitions =
                    followUpRecordsRequisitionDAO.findQuestionByRecordId(request.getRecordId());
            if (CommonUtils.isNotEmpty(followUpRecordsRequisitions)) {
                if (RouteDetailTypeEnum.MZFZ.getType().equals(followUpRecords.getRouteDetailType().toString())) {
                    //门诊复诊如果前端传入问卷id不为空要替换原有的问卷
                    FollowUpRecordsRequisition requisition = followUpRecordsRequisitions.get(0);
                    requisition.setQuestionnaireId(request.getQuestionnaireId());
                    requisition.setQuestionnaireName(request.getQuestionnaireName());
                    requisition.setUserInfoId(request.getUserInfoId());
                    requisition.setModifyDt(new Date());
                    followUpRecordsRequisitionDAO.update(requisition);
                } else {
                    //其他类型的，产品说只会存在一个问卷，严格点还是比较问卷id保存结果，避免出现多问卷的情况下出错
                    for (FollowUpRecordsRequisition followUpRecordsRequisition :
                            followUpRecordsRequisitions) {
                        if (request.getQuestionnaireId().equals(followUpRecordsRequisition.getQuestionnaireId())) {
                            followUpRecordsRequisition.setUserInfoId(request.getUserInfoId());
                            followUpRecordsRequisition.setModifyDt(new Date());
                            followUpRecordsRequisitionDAO.update(followUpRecordsRequisition);
                        }
                    }
                }

            }
        }

        //关联采集记录
        if (CommonUtils.isNotNull(request.getCollectId())) {
            patientMedicalDataCollectDAO.updateCollectDateFollowRecordId(request.getRecordId(), request.getCollectId());
        }

        if (FollowUpStatusEnum.FINISH.getStatus() == followUpRecords.getFollowUpStatus()
                || FollowUpStatusEnum.SUSPEND.getStatus() == followUpRecords.getFollowUpStatus()
                || FollowUpStatusEnum.CANCEL.getStatus() == followUpRecords.getFollowUpStatus()) {
            //生成下一次随访计划
            createNextFollowUpRecords(followUpRecords);
        }
    }

    /**
     * @description: 保存专科随访随访记录
     * @author: chenJij@bsoft.com.cn
     * @date: 2021/10/31 23:14
     * @param: request
     * @return: void
     */
    @Override
    @RpcService
    public void saveHmFollowUpResult(SaveFollowUpResultRequest request) throws ControllerException {
        FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord = fusTeamChronicGroupRecordDAO.get(request.getTeamChronicGroupId());
        if (null == fusTeamChronicGroupRecord) {
            throw new ControllerException("该患者未查到入组记录");
        }
        FollowUpRecords followUpRecords = new FollowUpRecords();
        followUpRecords.setRecordId(0L);
        followUpRecords.setOrganizationId(fusTeamChronicGroupRecord.getOrganizationId());
        followUpRecords.setRouteDetailType(Byte.valueOf(RouteDetailTypeEnum.JKJC.getType()));
        followUpRecords.setDiseaseTypeId(fusTeamChronicGroupRecord.getChronicDiseaseId());
        followUpRecords.setDiseaseTypeName(fusTeamChronicGroupRecord.getChronicDiseaseName());
        followUpRecords.setDepartmentId(fusTeamChronicGroupRecord.getDepartmentId());
        followUpRecords.setDepartmentName(fusTeamChronicGroupRecord.getDepartmentName());
        followUpRecords.setDoctorId(fusTeamChronicGroupRecord.getDoctorId());
        followUpRecords.setDocId(fusTeamChronicGroupRecord.getDocId());
        followUpRecords.setDoctorName(fusTeamChronicGroupRecord.getDoctorName());
        followUpRecords.setPatientId(fusTeamChronicGroupRecord.getPatientId());
        followUpRecords.setCardType(fusTeamChronicGroupRecord.getCardType());
        followUpRecords.setCardNumber(fusTeamChronicGroupRecord.getCardNumber());
        followUpRecords.setPatientName(fusTeamChronicGroupRecord.getPersonName());
        followUpRecords.setPatientSex(fusTeamChronicGroupRecord.getPersonSex());
        followUpRecords.setPatientAge(fusTeamChronicGroupRecord.getAge() == null ? 0 : fusTeamChronicGroupRecord.getAge().intValue());
        followUpRecords.setTelephone(fusTeamChronicGroupRecord.getTelephone());
        followUpRecords.setAddress(fusTeamChronicGroupRecord.getAddress());
        followUpRecords.setPlanTime(new Date());
        followUpRecords.setCreateId("");
        followUpRecords.setCreateTime(new Date());
        followUpRecords.setStopId("");
        followUpRecords.setStopTime(new Date());
        followUpRecords.setRouteId(0L);
        followUpRecords.setRouteName("");
        followUpRecords.setRouteDetailId(0L);
        followUpRecords.setGmtCreate(new Date());
        followUpRecords.setIsNotify((byte) 0);
        followUpRecords.setIsRead((byte) 0);
        followUpRecords.setPlanNotifyDate(new Date());
        followUpRecords.setNotifyStatus((byte) 0);
        followUpRecords.setMedicalRecordId(request.getQuestionnaireId());
        followUpRecords.setMedicalRecordName(request.getQuestionnaireName());
        followUpRecords.setPatientMedicalCardNumber(fusTeamChronicGroupRecord.getPatientMedicalCardNumber());
        followUpRecords.setPatientMedicalCardType(fusTeamChronicGroupRecord.getPatientMedicalCardType());
        followUpRecords.setTeamChronicGroupId(fusTeamChronicGroupRecord.getTeamChronicGroupId());
        followUpRecords.setMedicalTeamId(fusTeamChronicGroupRecord.getMedicalTeamId());
        followUpRecords.setMedicalTeamName(fusTeamChronicGroupRecord.getMedicalTeamName());
        followUpRecords.setAbnormalReadFlag(Constants.ZORE_STRING);
        followUpRecords.setMedicalRecordId(request.getQuestionnaireId());
        followUpRecords.setMedicalRecordName(request.getQuestionnaireName());


        if (StringUtils.isNotEmpty(followUpRecords.getMedicalRecordId()) && CommonUtils.isNull(request.getUserInfoId()) && "1".equals(request.getResultCode().toString())) {
            //执行结果失败的时候可以不用传答案id
            throw new ControllerException("问卷传入参数不能为空");
        }

        if (CommonUtils.isNotNull(request.getUserInfoId())) {
            //进行重复的userInfoId校验
            FollowUpRecords tempFollowUpRecords =
                    followUpRecordsDAO.getByUserInfoId(request.getUserInfoId());
            if (tempFollowUpRecords != null && !tempFollowUpRecords.getRecordId().equals(followUpRecords.getRecordId())) {
                throw new ControllerException("问卷填写答案唯一标识userInfoId与已有数据重复");
            }
        }
        followUpRecords.setResultCode(request.getResultCode());
        followUpRecords.setFollowUpStatus((byte) 2);
        followUpRecords.setExecuteId(request.getOperatorId());
        Date now = new Date();
        followUpRecords.setExecuteTime(now);
        followUpRecords.setGmtModified(now);
        followUpRecords.setAuditStatus((byte) 0);
        followUpRecords.setUserInfoId(request.getUserInfoId());
        followUpRecords.setCreateId(UserRoleToken.getCurrent().getUserId());
        followUpRecords.setExecuteName(request.getOperatorName());
        if (StringUtils.isNotEmpty(request.getAnswerAbnormal())) {
            followUpRecords.setAnswerAbnormal(request.getAnswerAbnormal());
        }
        if (CommonUtils.isNotNull(request.getMedicalRecordUploadFlag())) {
            followUpRecords.setMedicalRecordUploadFlag(request.getMedicalRecordUploadFlag());
        }
        followUpRecords.setAutoCreateFlag(Constants.ZORE_STRING);
        followUpRecordsDAO.save(followUpRecords);

        FollowUpRecordsRequisition insert = new FollowUpRecordsRequisition();
        insert.setFormId(KeyGenerator.randomGenerate());
        insert.setRecordId(followUpRecords.getRecordId());
        insert.setCreateDt(new Date());
        insert.setModifyDt(new Date());
        insert.setQuestionnaireId(request.getQuestionnaireId());
        insert.setQuestionnaireName(request.getQuestionnaireName());
        insert.setUserInfoId(request.getUserInfoId());

        followUpRecordsRequisitionDAO.insertSelective(insert);

        //生成下一次随访计划
        createNextFollowUpRecords(followUpRecords);
        return;
    }

    /**
     * @param request
     * @throws
     * @description: 终止随访计划
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/7/23 10:39
     */
    @Override
    @RpcService
    public void stopExecutionList(StopExecutionListRequest request) throws ControllerException {

        if (CommonUtils.isNotEmpty(request.getRecordIdArr())) {
            if (CommonUtils.isEmpty(request.getOperatorId())) {
                throw new ControllerException(ResultCode.ERROR, "入参不能为空");
            }
            List<Long> medicalTeamIds = docTeamMemberRpcService.findMedicalTeamIdsByDoctorId(request.getOperatorId());
            if (CommonUtils.isNotEmpty(medicalTeamIds)) {
                followUpRecordsDAO.stopFollowUpPlanByrecordIds(medicalTeamIds, request);
            }
        } else {
            if (CommonUtils.isEmpty(request.getRecordId())) {
                throw new ControllerException(ResultCode.ERROR, "入参不能为空");
            }
            FollowUpRecords followUpRecords = followUpRecordsDAO.get(request.getRecordId());
            if (followUpRecords == null) {
                throw new ControllerException("随访执行计划不存在");
            } else {
                if (Objects.equals(followUpRecords.getFollowUpStatus(), (byte) 1)) {
                    throw new ControllerException("随访执行计划已经被执行，不允许终止");
                } else if (followUpRecords.getFollowUpStatus() == (byte) 9) {
                    throw new ControllerException("随访执行计划已经被终止，请刷新");
                } else {
//				followUpRecords.setResultCode((byte) 2);
                    Date now = new Date();
                    followUpRecords.setStopId(request.getOperatorId());
                    followUpRecords.setStopTime(now);
                    followUpRecords.setStopType(request.getCancelType());
                    followUpRecords.setStopReason(request.getCancelReason());
                    //随访状态：0未随访 1 已随访 9 已终止
                    followUpRecords.setFollowUpStatus((byte) 9);
                    followUpRecords.setGmtModified(now);
                    followUpRecordsDAO.update(followUpRecords);

                    //生成下一次随访计划
                    createNextFollowUpRecords(followUpRecords);
                }
            }
        }
        return;
    }

    /**
     * 终止该病人所有的随访计划
     *
     * @param request
     * @throws ControllerException
     */
    @Override
    @RpcService
    public void stopAllExecutionList(StopAllExecutionListRequest request) throws ControllerException {

        //查询出该病人所有待执行的计划
        List<FollowUpRecords> followUpRecords = followUpRecordsDAO.findPatientAllPlan(request.getPatientId(), request.getOrganizationId());
        if (CollectionUtils.isEmpty(followUpRecords)) {
            throw new ControllerException("随访执行计划不存在");
        }
        followUpRecords.forEach(record -> {
            if ((record.getFollowUpStatus() == (byte) 9) || (record.getFollowUpStatus() == (byte) 1)) {
                return;
            }
//				followUpRecords.setResultCode((byte) 2);
            Date now = new Date();
            record.setStopId(request.getDocId());
            record.setStopTime(now);
            record.setStopType(request.getCancelType());
            record.setStopReason(request.getCancelReason());
            //随访状态：0未随访 1 已随访 9 已终止
            record.setFollowUpStatus((byte) 9);
            record.setGmtModified(now);
            followUpRecordsDAO.update(record);

            //生成下一次随访计划
            try {
                createNextFollowUpRecords(record);
            } catch (ControllerException e) {
                logger.error("生成下一次随访计划失败", e);
            }

        });
    }

    /**
     * @description: 生成下一次随访计划
     * @param: followUpRecords
     * @return: void
     */
    @Override
    public void createNextFollowUpRecords(FollowUpRecords followUpRecords) throws ControllerException {

        //状态变更后需要判断随访计划生成记录的状态不是终止的则生成下一次随访计划
        FollowUpPlanProduceRecord followUpPlanProduceRecord =
                followUpPlanProduceRecordDAO.getByRouteDetailId(followUpRecords.getRouteDetailId(), followUpRecords.getTeamChronicGroupId());
        if (followUpPlanProduceRecord != null && 1 == followUpPlanProduceRecord.getStatus()) {
            //生成随访计划
            //计算随访计划开始时间
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(followUpRecords.getGmtModified());
            calendar.add(Calendar.DAY_OF_MONTH, followUpPlanProduceRecord.getFollowUpFrequencyNumber());
            Date startPlanTime = calendar.getTime();
            //保存随访计划（随访表单、健康宣教、推荐科室、复诊项目、监测范围等数据要一并保存，和随访计划id关联）、
            //随访计划生成记录(包括这次生成的是第几次，是临时还是长期的，时间间隔是多少，状态(执行中、停止))
            FollowUpRoute followUpRoute = followUpRouteDAO.get(followUpPlanProduceRecord.getRouteId());
            FollowUpRouteDetail followUpRouteDetail =
                    followUpRouteDetailDAO.get(followUpPlanProduceRecord.getRouteId());
            FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecordEntity =
                    fusTeamChronicGroupRecordDAO.get(followUpPlanProduceRecord.getTeamChronicGroupId());
            List<FusTeamChronicGroupRecordEntity> fusTeamChronicGroupRecordEntities = new ArrayList<>();
            fusTeamChronicGroupRecordEntities.add(fusTeamChronicGroupRecordEntity);
            produceData(followUpRecords.getDiseaseTypeId(), followUpRecords, followUpRoute, followUpRouteDetail,
                    fusTeamChronicGroupRecordEntities, startPlanTime);
        }
    }

    /**
     * @param request
     * @throws
     * @description: 用户端查看随访计划更新状态
     * @return: org.atag.core.base.BaseResponse
     * @author: liwl
     * @date: 2020/10/9 10:39
     */
    @Override
    @RpcService
    public void readFollowUpPlan(StopExecutionListRequest request) throws ControllerException {
        FollowUpRecords followUpRecords = followUpRecordsDAO.get(request.getRecordId());
        if (followUpRecords == null) {
            throw new ControllerException("随访执行计划不存在");
        } else {
            followUpRecordsDAO.updateFollowUpPlanReadById(request.getRecordId());
            return;
        }
    }


    @Override
    @RpcService
    public PageInfo<ExecutionListByPatientResp> queryExecutionListByPatient(QueryExecutionListByPatientReq byPatientReq) throws ControllerException {
        List<ExecutionListByPatientResp> list;
        if (CommonUtils.isEmpty(byPatientReq.getFollowupType())){
            ArrayList<String> type = new ArrayList<>();
            type.add("1");
            type.add("2");
            type.add("3");
            byPatientReq.setFollowupType(type);
        }
        if(CommonUtils.isNotEmpty(byPatientReq.getTeamChronicGroupId())){
            FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecordEntity = fusTeamChronicGroupRecordDAO.get(byPatientReq.getTeamChronicGroupId());
            if(null != fusTeamChronicGroupRecordEntity){
                byPatientReq.setDiseaseTypeId(fusTeamChronicGroupRecordEntity.getChronicDiseaseId());
            }
        }

        if (CommonUtils.isEmpty(byPatientReq.getPatientId()) && CommonUtils.isNotEmpty(byPatientReq.getMpiId())) {
            //查询病人id列表
            List<FusTeamChronicGroupRecordEntity> fusRecords =
                    fusTeamChronicGroupRecordDAO.findFusRecordsByPersonId(byPatientReq.getMpiId());
            if (CommonUtils.isNotEmpty(fusRecords)) {
                byPatientReq.setPatientId(fusRecords.get(0).getPatientId());
            }
        }
        if (CommonUtils.isEmpty(byPatientReq.getPatientId())
                && (CommonUtils.isEmpty(byPatientReq.getCardType()) || CommonUtils.isEmpty(byPatientReq.getCardNumber()))) {
            throw new ControllerException("patientId和证件信息不能同时为空");
        }
        try {
            Long count = followUpRecordsDAO.countExecutionListByPatient(byPatientReq);
            if (count > 0) {
                list = followUpRecordsDAO.queryExecutionListByPatient(byPatientReq);
                HashMap<String, String> doctorCodeMap = new HashMap<>();
                if (CommonUtils.isNotEmpty(list)) {
                    for (ExecutionListByPatientResp resp : list) {
                        List<QuestionVo> questionVos = new ArrayList<>();
                        List<QuestionVo> educationList = new ArrayList<>();
                        if (FollowTypeEnum.FUS_SPECIALIST.getType().equals(resp.getFollowType())) {
                            //专科随访 支持
                            List<FollowUpRecordsRequisition> questionByRecords = followUpRecordsRequisitionDAO.findQuestionByRecordId(Long.valueOf(resp.getRecordId()));
                            //宣教表单
                            List<FollowUpRecordsEducation> educations = followUpRecordsEducationDAO.findQuestionByRecordId(Long.valueOf(resp.getRecordId()));
                            if (CommonUtils.isNotEmpty(questionByRecords)) {
                                questionByRecords.forEach(q -> {
                                    QuestionVo questionVo = new QuestionVo();
                                    questionVo.setQuestionId(q.getQuestionnaireId());
                                    questionVo.setQuestionName(q.getQuestionnaireName());
                                    questionVo.setUserInfoId(q.getUserInfoId());
                                    questionVos.add(questionVo);
                                });
                            }
                            if (CommonUtils.isNotEmpty(educations)) {
                                educations.forEach(e -> {
                                    QuestionVo questionVo = new QuestionVo();
                                    questionVo.setQuestionId(e.getEducationId() + "");
                                    questionVo.setQuestionName(e.getEducationName());
                                    questionVo.setId(e.getId());
                                    questionVo.setEducationId(e.getEducationId()+"");
                                    questionVo.setEducationName(e.getEducationName());
                                    questionVo.setEducationStatus(StringUtils.isEmpty(e.getEducationStatus())?"0":e.getEducationStatus());
                                    educationList.add(questionVo);
                                });
                            }
                        } else if (FollowTypeEnum.FUS_AFTER.getType().equals(resp.getFollowType())) {
                            List<FusAfterRequisitionRecord> questions = fusAfterRequisitionRecordDAO.findQuestionByRecordId(resp.getRecordId());
                            List<FusAfterHealthEducation> healthEducations = fusAfterHealthEducationDAO.queryHealthEducationByRecordId(resp.getRecordId());
                            if (CommonUtils.isNotEmpty(questions)) {
                                questions.forEach(q -> {
                                    QuestionVo questionVo = new QuestionVo();
                                    questionVo.setQuestionId(q.getQuestionnaireId());
                                    questionVo.setQuestionName(q.getExecuteName());
                                    questionVos.add(questionVo);
                                });
                            }
                            if (CommonUtils.isNotEmpty(healthEducations)) {
                                healthEducations.forEach(e -> {
                                    QuestionVo questionVo = new QuestionVo();
                                    questionVo.setQuestionId(e.getEducationId() + "");
                                    questionVo.setQuestionName(e.getEducationName());
                                    educationList.add(questionVo);
                                });
                            }
                        }
                        resp.setQuestionList(questionVos);
                        resp.setEducationList(educationList);
                        if (StringUtils.isEmpty(resp.getDoctorId())){
                            continue;
                        }
                        if (StringUtils.isNotEmpty(doctorCodeMap.get(resp.getDoctorId()))){
                            resp.setDoctorCode(doctorCodeMap.get(resp.getDoctorId()));
                        }else{
                            List<String> doctorIds = orgDoctorsService.findDoctorIdByLocalDoctorId(resp.getDoctorId());
                            if (CommonUtils.isEmpty(doctorIds)){
                                continue;
                            }
                            String doctorUserId = docIdentityService.getDoctorUserId(doctorIds.get(0));
                            //用doctorUserId拿到personInfo，根据personInfo中的字典值cd拿到医生编码
                            Map<String, Object> personInfo = AppContextHolder.get().getBean(IPersonService.class).getByUserId(doctorUserId);
                            if (CommonUtils.isNotEmpty(personInfo)) {
                                resp.setDoctorCode((String) personInfo.get("cd"));
                                doctorCodeMap.put(resp.getDoctorId(),resp.getDoctorCode());
                            }
                        }
                    }
                    PageInfo<ExecutionListByPatientResp> pageInfo = new PageInfo(list);
                    pageInfo.setPageNum(byPatientReq.getPageNo());
                    pageInfo.setPageSize(byPatientReq.getPageSize());
                    pageInfo.setTotal(count);
                    return pageInfo;
                }
            }
        } catch (Exception e) {
            logger.error("queryExecutionListByPatient-----" + e.getMessage());
            throw new ControllerException("请求失败" + e.getMessage());
        }
        return new PageInfo();
    }

    /**
     * @param followUpRoute
     * @param operatorId
     * @throws
     * @description: 生成随访计划记录
     * @return: org.atag.core.base.BaseResponse
     * @author: tongtp
     * @date: 2020/7/21 15:29
     */
    private BaseResponse doProduceExecutionList(FollowUpRoute followUpRoute, String operatorId) throws ControllerException {
        //病种id/慢病id
        Long diseaseTypeId = followUpRoute.getDiseaseTypeId();
        //拼装随访计划记录数据,可在循环外拼接的手动提取出代码避免多次执行
        FollowUpRecords followUpRecords = new FollowUpRecords();
        followUpRecords.setDiseaseTypeId(diseaseTypeId);
        followUpRecords.setDiseaseTypeName(followUpRoute.getDiseaseTypeName());
        //随访状态：0未随访 1 已随访 9 已终止
        followUpRecords.setFollowUpStatus(FollowUpStatusEnum.READY.getStatus());
        followUpRecords.setCreateId(operatorId);
        followUpRecords.setRouteId(followUpRoute.getRouteId());
        followUpRecords.setRouteName(followUpRoute.getRouteName());
        //通知状态：0 未通知 1 已通知
        followUpRecords.setNotifyStatus((byte) 0);
        //查询随访路径详情
        List<FollowUpRouteDetail> followUpRouteDetails =
                followUpRouteDetailDAO.queryByRouteId(followUpRoute.getRouteId());
        if (!CollectionUtils.isEmpty(followUpRouteDetails)) {
            for (FollowUpRouteDetail followUpRouteDetail : followUpRouteDetails) {
                handleFollowUpRouteDetail(diseaseTypeId, followUpRoute, followUpRecords, followUpRouteDetail);
            }
            return BaseRespUtil.setResultSuccess();
        } else {
            return BaseRespUtil.setResultError("RouteId={" + followUpRoute.getRouteId() + "}随访路径详情为空，无法生成随访计划");
        }
    }

    /**
     * @param diseaseTypeId
     * @param followUpRecords
     * @param followUpRouteDetail
     * @throws
     * @description: 处理随访路径详情
     * @return: void
     * @author: tongtp
     * @date: 2020/7/28 17:26
     */
    private void handleFollowUpRouteDetail(Long diseaseTypeId, FollowUpRoute followUpRoute, FollowUpRecords followUpRecords, FollowUpRouteDetail followUpRouteDetail) throws ControllerException {
        //拼装随访计划记录数据,可在循环外拼接的手动提取出代码避免多次执行
        followUpRecords.setRouteDetailType(followUpRouteDetail.getRouteDetailType());
        followUpRecords.setRouteDetailId(followUpRouteDetail.getRouteDetailId());
        followUpRecords.setIsNotify(followUpRouteDetail.getIsNotify());
        followUpRecords.setMedicalRecordId(followUpRouteDetail.getMedicalRecordId());
        followUpRecords.setMedicalRecordName(followUpRouteDetail.getMedicalRecordName());

        //随访路径详情id
        Long routeDetailId = followUpRouteDetail.getRouteDetailId();
        //循环执行机制 0 不执行 1 执行
        Byte isLoopExecute = followUpRouteDetail.getIsLoopExecute();
        //查询随访路径详情因素
        //factorFlag因素类型
        List<FollowUpRouteDetailFactor> followUpRouteDetailFactors =
                followUpRouteDetailFactorDAO.queryByRouteDetailId(routeDetailId, FactorFlagEnum.START.getType());
        if (CommonUtils.isNotEmpty(followUpRouteDetailFactors)) {
            //遍历的所有因素依次执行筛选:
            //and相连的因素检索出来的数据求交集，遇到OR连接符时，把前面检索出来的数据集合保存，
            //后面检索出来的数据在遇到下一个OR连接符或者结束时与前面检索出来的数据集合求并集
            List<String> previousList = new ArrayList<>();
            //病人因素信息存储集合，key是病人id，value是按顺序存储的因素数据集合
            Map<String, List<FactorData>> patientInfoMap = new HashMap<>(256);
            //处理因素列表得到人员信息集合和因素数据集合
            followUpCommonService.handleFactorList(followUpRoute, isLoopExecute, followUpRouteDetailFactors,
                    previousList, patientInfoMap);

            //去重
            if (!CollectionUtils.isEmpty(previousList)) {
                HashSet<String> h = new HashSet(previousList);
                previousList.clear();
                previousList.addAll(h);
            }

            if (CollectionUtils.isEmpty(previousList)) {
                logger.info("RouteDetailId:{},子路径没有检索到符合条件的人员数据", routeDetailId);
            } else {
                List<FusTeamChronicGroupRecordEntity> fusTeamChronicGroupRecordEntities = fusTeamChronicGroupRecordDAO.queryByPatientIdList(previousList, diseaseTypeId);

                saveProduceData(diseaseTypeId, fusTeamChronicGroupRecordEntities, followUpRecords, followUpRouteDetail, followUpRoute, patientInfoMap);
                logger.info("RouteDetailId:{},子路径检索到符合条件的人员数据如下:{}", routeDetailId, JSON.toJSONString(previousList));

            }
        } else {
            //通过病种if查询未生成过随访计划的入组记录
            List<FusTeamChronicGroupRecordEntity> fusTeamChronicGroupRecordEntities =
                    produceExecutionListDAO.queryByChronicDiseaseId(diseaseTypeId, routeDetailId);
            saveProduceData(diseaseTypeId, fusTeamChronicGroupRecordEntities, followUpRecords, followUpRouteDetail,
                    followUpRoute, null);
        }
    }

    /**
     * @description: 批量保存随访计划
     * @param: diseaseTypeId
     * @param: fusTeamChronicGroupRecordEntities
     * @param: followUpRecords
     * @param: followUpRouteDetail
     * @param: followUpRoute
     * @param: patientInfoMap
     * @return: void
     */
    private void saveProduceData(Long diseaseTypeId, List<FusTeamChronicGroupRecordEntity> fusTeamChronicGroupRecordEntities, FollowUpRecords followUpRecords,
                                 FollowUpRouteDetail followUpRouteDetail, FollowUpRoute followUpRoute, Map<String, List<FactorData>> patientInfoMap) throws ControllerException {
        if (CommonUtils.isEmpty(fusTeamChronicGroupRecordEntities)) {
            logger.info("fusTeamChronicGroupRecordEntities:{},入组纪录没有检索到符合条件的人员数据", followUpRouteDetail.getRouteDetailId());
            return;
        }
        for (FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecordEntity : fusTeamChronicGroupRecordEntities) {
            //得到要生成随访计划的就诊类型记录之后，需要判断该子路径有没有给该就诊类型记录生成过。生成过则不用再生成了。
            FollowUpPlanProduceRecord followUpPlanProduceRecord =
                    followUpPlanProduceRecordDAO.getByRouteDetailId(followUpRouteDetail.getRouteDetailId(), fusTeamChronicGroupRecordEntity.getTeamChronicGroupId());
            if (followUpPlanProduceRecord == null) {
                //生成随访计划
                //计算随访计划开始时间-第一次随访计划的计划执行时间
                List<FactorData> factorDataList = null;
                if (null != patientInfoMap) {
                    factorDataList = patientInfoMap.get(fusTeamChronicGroupRecordEntity.getPatientId());
                }
                Date startPlanTime = followUpCommonService.getStartPlanTime(followUpRouteDetail,
                        factorDataList,
                        followUpRoute.getFollowType(), fusTeamChronicGroupRecordEntity.getAuditTime()
                        , null);
                //保存随访计划（随访表单、健康宣教、推荐科室、复诊项目、监测范围等数据要一并保存，和随访计划id关联）、
                //随访计划生成记录(包括这次生成的是第几次，是临时还是长期的，时间间隔是多少，状态(执行中、停止))

                produceData(diseaseTypeId, followUpRecords, followUpRoute, followUpRouteDetail,
                        fusTeamChronicGroupRecordEntities, startPlanTime);
                //保存因素数据使用记录
                followUpCommonService.saveFusFactorDataRecord(followUpRoute.getFollowType(),
                        followUpRouteDetail.getRouteDetailId(),
                        factorDataList, fusTeamChronicGroupRecordEntity.getTeamChronicGroupId(),
                        null);
            } else {
                logger.info("该子路径给该入组记录生成过随访计划，跳过生成;fusTeamChronicGroupRecordEntity:{}," +
                                "fusAfterPlanProduceRecord:{}",
                        JSON.toJSONString(fusTeamChronicGroupRecordEntity));
            }
        }
    }

    /**
     * @param diseaseTypeId
     * @param followUpRecords
     * @param followUpRouteDetail
     * @param fusTeamChronicGroupRecordEntities
     * @param startPlanTime
     * @throws
     * @description: 产生数据
     * @return: void
     * @author: tongtp
     * @date: 2020/7/30 17:16
     */
    private void produceData(Long diseaseTypeId, FollowUpRecords followUpRecords, FollowUpRoute followUpRoute, FollowUpRouteDetail followUpRouteDetail,
                             List<FusTeamChronicGroupRecordEntity> fusTeamChronicGroupRecordEntities, Date startPlanTime) throws ControllerException {
        Long routeDetailId = followUpRouteDetail.getRouteDetailId();
        Calendar planTimeInstance = Calendar.getInstance();
        Calendar advanceNotifyDateInstance = Calendar.getInstance();
        //随访频次次数,非长期是1
        Integer followUpFrequencyNumber = 1;
        //随访间隔时间-天数
        Integer intervalTime = 0;
        //随访提前通知时间-天数
        Integer advanceNotifyDate = 1;
        //随访频率，1临时  2长期
        if (followUpRouteDetail.getFollowUpFrequency() != null && followUpRouteDetail
                .getFollowUpFrequency() == (byte) 2) {
            //长期
            //随访频次次数
            followUpFrequencyNumber = followUpRouteDetail.getFollowUpFrequencyNumber();
            //随访频次时间，长期时需要填写，1每天一次,2每周一次,3每4周一次,4每月一次,5每3月一次,6每半年一次,7每年一次
            Byte followUpFrequencyTime = followUpRouteDetail.getFollowUpFrequencyTime();
            intervalTime = getIntervalTime(diseaseTypeId, followUpRouteDetail, routeDetailId,
                    intervalTime, followUpFrequencyTime);
            if (intervalTime == null) {
                return;
            }
        }
        //是否通知患者，0不通知，1通知
        if (followUpRouteDetail.getIsNotify() == (byte) 1) {
            advanceNotifyDate = followUpCommonService.getAdvanceNotifyDate(diseaseTypeId, followUpRouteDetail,
                    routeDetailId
                    , advanceNotifyDate);
            if (advanceNotifyDate == null) {
                return;
            }
        }

        List<FollowUpRecordsContent> followUpRecordsContents = new ArrayList<>();
        List<FollowUpRecordsRequisition> requisitions = new ArrayList<>();
        List<FollowUpRecordsEducation> educations = new ArrayList<>();

        //处理随访内容详情
        handleFollowUpRecordsContents(followUpRouteDetail.getRouteId(), routeDetailId, followUpRecordsContents, requisitions, educations);
        for (FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord :
                fusTeamChronicGroupRecordEntities) {
            if(followUpRouteDetail.getIsLoopExecute() == (byte)0){
                FollowUpPlanProduceRecord produceRecord =
                        followUpPlanProduceRecordDAO.getByRouteDetailId(followUpRouteDetail.getRouteDetailId(), fusTeamChronicGroupRecord.getTeamChronicGroupId());
                if(Objects.nonNull(produceRecord)){
                    continue;
                }
            }
            //保存随访执行计划
            saveFollowUpRecords(diseaseTypeId, followUpRecords, followUpRoute, followUpRouteDetail, routeDetailId,
                    planTimeInstance, advanceNotifyDateInstance, followUpFrequencyNumber, intervalTime,
                    advanceNotifyDate, followUpRecordsContents, fusTeamChronicGroupRecord, startPlanTime,
                    requisitions, educations);
        }
    }

    /**
     * @throws
     * @description: 保存随访执行计划
     * @return: void
     * @author: tongtp
     * @date: 2020/7/30 17:18
     */
    private void saveFollowUpRecords(Long diseaseTypeId, FollowUpRecords followUpRecords, FollowUpRoute followUpRoute, FollowUpRouteDetail followUpRouteDetail,
                                     Long routeDetailId, Calendar planTimeInstance, Calendar advanceNotifyDateInstance, Integer followUpFrequencyNumber,
                                     Integer intervalTime, Integer advanceNotifyDate, List<FollowUpRecordsContent> followUpRecordsContents,
                                     FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord, Date startPlanTime, List<FollowUpRecordsRequisition> requisitions,
                                     List<FollowUpRecordsEducation> educations) throws ControllerException {
        if (startPlanTime == null) {
            logger.info("diseaseTypeId:{},RouteDetailId:{},TimeNodeType:{}," +
                            "TeamChronicGroupId:{}," +
                            "没有找到合适的随访计划时间起点",
                    diseaseTypeId,
                    routeDetailId, followUpRouteDetail.getTimeNodeType()
                    , fusTeamChronicGroupRecord.getTeamChronicGroupId());
            return;
        }
        //拼装随访计划记录数据
        Date now = new Date();
        followUpRecords.setOrganizationId(fusTeamChronicGroupRecord.getOrganizationId());
        followUpRecords.setDepartmentId(fusTeamChronicGroupRecord.getDepartmentId());
        followUpRecords.setDepartmentName(fusTeamChronicGroupRecord.getDepartmentName());
        followUpRecords.setDoctorId(fusTeamChronicGroupRecord.getDoctorId());
        followUpRecords.setDocId(fusTeamChronicGroupRecord.getDocId());
        followUpRecords.setDoctorName(fusTeamChronicGroupRecord.getDoctorName());
        followUpRecords.setPatientId(fusTeamChronicGroupRecord.getPatientId());
        followUpRecords.setCardType(fusTeamChronicGroupRecord.getCardType());
        followUpRecords.setCardNumber(fusTeamChronicGroupRecord.getCardNumber());
        followUpRecords.setPatientMedicalCardType(fusTeamChronicGroupRecord.getPatientMedicalCardType());
        followUpRecords.setPatientMedicalCardNumber(fusTeamChronicGroupRecord.getPatientMedicalCardNumber());
        followUpRecords.setPatientName(fusTeamChronicGroupRecord.getPersonName());
        followUpRecords.setPatientSex(fusTeamChronicGroupRecord.getPersonSex());
        followUpRecords.setPatientAge(fusTeamChronicGroupRecord.getAge() == null ? null :
                fusTeamChronicGroupRecord.getAge().intValue());
        followUpRecords.setTelephone(fusTeamChronicGroupRecord.getTelephone());
        followUpRecords.setCreateTime(now);
        followUpRecords.setTeamChronicGroupId(fusTeamChronicGroupRecord.getTeamChronicGroupId());
        followUpRecords.setMedicalTeamId(fusTeamChronicGroupRecord.getMedicalTeamId());
        followUpRecords.setMedicalTeamName(fusTeamChronicGroupRecord.getMedicalTeamName());
        followUpRecords.setGmtCreate(now);
        followUpRecords.setGmtModified(now);
        followUpRecords.setAbnormalReadFlag(Constants.ZORE_STRING);
        followUpRecords.setAnswerAbnormal(Constants.TWO_STRING);
        followUpRecords.setAutoCreateFlag(Constants.ZORE_STRING);
        if ("1".equals(followUpRoute.getCheckPlan())) {
            followUpRecords.setAuditStatus((byte) 1);
        } else {
            followUpRecords.setAuditStatus((byte) 0);
        }
        //保存随访计划生产计划表和随访编辑器答案fus_answer、随访路径详情follow_up_route_detail的关联关系表fus_answer_route_record
        saveFollowUpPlanProduceRecord(followUpRouteDetail, routeDetailId, fusTeamChronicGroupRecord, now);
        //保存随访执行计划
        followUpRecords.setRecordId(0L);
        followUpRecords.setPlanTime(startPlanTime);

        //是否通知患者，0不通知，1通知
        if (followUpRouteDetail.getIsNotify() == (byte) 1) {
            advanceNotifyDateInstance.setTime(followUpRecords.getPlanTime());
            advanceNotifyDateInstance.add(Calendar.DAY_OF_YEAR, advanceNotifyDate);
            followUpRecords.setPlanNotifyDate(advanceNotifyDateInstance.getTime());
        }
        followUpRecordsDAO.save(followUpRecords);
        if (!CollectionUtils.isEmpty(followUpRecordsContents)) {
            for (FollowUpRecordsContent followUpRecordsContent :
                    followUpRecordsContents) {
                followUpRecordsContent.setFollowUpRecordsContentId(0L);
                followUpRecordsContent.setRecordId(followUpRecords.getRecordId());
                followUpRecordsContent.setEducationStatus(Constants.ZORE_STRING);
                followUpRecordsContentDAO.save(followUpRecordsContent);
            }
        }
        //保存表单和宣教
        if (!CollectionUtils.isEmpty(requisitions)) {
            requisitions.forEach(r -> {
                r.setFormId(KeyGenerator.randomGenerate());
                r.setRecordId(followUpRecords.getRecordId());
                r.setCreateId("");
                r.setCreateDt(now);
                r.setModifyDt(now);
                followUpRecordsRequisitionDAO.save(r);
            });
        }
        if (!CollectionUtils.isEmpty(educations)) {
            educations.forEach(e -> {
                e.setId(KeyGenerator.randomGenerate());
                e.setRecordId(followUpRecords.getRecordId());
                e.setCreateDt(now);
                e.setModifyDt(now);
                followUpRecordsEducationDAO.save(e);
            });
        }
    }


    /**
     * @param followUpRouteDetail
     * @param routeDetailId
     * @param fusTeamChronicGroupRecord
     * @param now
     * @throws
     * @description: 保存随访计划生产计划表
     * @return: void
     * @author: tongtp
     * @date: 2020/7/30 9:25
     */
    private void saveFollowUpPlanProduceRecord(FollowUpRouteDetail followUpRouteDetail, Long routeDetailId,
                                               FusTeamChronicGroupRecordEntity fusTeamChronicGroupRecord, Date now) throws ControllerException {
        FollowUpPlanProduceRecord produceRecord =
                followUpPlanProduceRecordDAO.getByRouteDetailId(followUpRouteDetail.getRouteDetailId(), fusTeamChronicGroupRecord.getTeamChronicGroupId());
        if (null != produceRecord) {
            produceRecord.setGmtModified(now);
            if (produceRecord.getStatus() == 2) {
                throw new ControllerException("随访生产计划已结束，无法新增随访计划");
            }
            produceRecord.setProducedTimes(produceRecord.getProducedTimes() + 1);
            followUpPlanProduceRecordDAO.update(produceRecord);
        } else {
            produceRecord = new FollowUpPlanProduceRecord();
            produceRecord.setRouteId(followUpRouteDetail.getRouteId());
            produceRecord.setTeamChronicGroupId(fusTeamChronicGroupRecord.getTeamChronicGroupId());
            produceRecord.setRouteDetailId(routeDetailId);
            //随访频率，1临时  2长期
            if (followUpRouteDetail.getFollowUpFrequency() != null && followUpRouteDetail
                    .getFollowUpFrequency() == (byte) 2) {
                //状态：1 开始 2 结束（随访频率临时的直接结束）
                produceRecord.setStatus((byte) 1);
            } else {
                //状态：1 开始 2 结束（随访频率临时的直接结束）
                produceRecord.setStatus((byte) 2);
                produceRecord.setEndTime(now);
            }
            produceRecord.setFollowUpFrequency(followUpRouteDetail.getFollowUpFrequency());
            produceRecord.setStartTime(now);
            produceRecord.setGmtCreate(now);
            produceRecord.setGmtModified(now);
            followUpPlanProduceRecordDAO.save(produceRecord);
        }

        //随访编辑器答案fus_answer与随访路径详情follow_up_route_detail的关联关系表，只有设置了循环执行属性的路径详情才会使用到这里的数据
        //但是保存，就算没有设置循环执行属性的路径详情也会记录fus_answer_route_record表信息，因为随访路径详情的属性是会变化的
        //先查询出来本次生成随访计划的该病种的所有答案，然后校验是否存在，再保存
        FusTeamChronicGroupRecordEntity teamChronicGroupRecord =
                fusTeamChronicGroupRecordDAO.get(fusTeamChronicGroupRecord.getTeamChronicGroupId());
        if (teamChronicGroupRecord != null) {
            String patientId = teamChronicGroupRecord.getPatientId();
            Integer patientMedicalCardType = teamChronicGroupRecord.getPatientMedicalCardType();
            String patientMedicalCardNumber = teamChronicGroupRecord.getPatientMedicalCardNumber();
            String cardType = teamChronicGroupRecord.getCardType();
            String cardNumber = teamChronicGroupRecord.getCardNumber();
            //这三组信息至少有一组不为空才往下执行
            if (CommonUtils.isNotNull(patientId) || (CommonUtils.isNotNull(patientMedicalCardType) && CommonUtils.isNotNull(patientMedicalCardNumber))
                    || (CommonUtils.isNotNull(cardType) && CommonUtils.isNotNull(cardNumber))) {
                //虽然目前随访路径执行没有用到所有的答案表，但是这里针对所有答案表数据都进行记录
                Long diseaseTypeId = teamChronicGroupRecord.getChronicDiseaseId();
                Set<String> reportIds = new HashSet<>();
                reportIds.addAll(fusAnswerCheckReportInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                reportIds.addAll(fusAnswerDiagnosisInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                reportIds.addAll(fusAnswerDrugInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                reportIds.addAll(fusAnswerInHospitalInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                reportIds.addAll(fusAnswerInspectionReportInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                reportIds.addAll(fusAnswerOperativeInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                reportIds.addAll(fusAnswerOutpatientInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                reportIds.addAll(fusAnswerTreatmentInfoDAO.queryReportId(diseaseTypeId, patientId,
                        patientMedicalCardType,
                        patientMedicalCardNumber, cardType, cardNumber));
                if (!CollectionUtils.isEmpty(reportIds)) {
                    Long count;
                    for (String reportId :
                            reportIds) {
                        count =
                                fusAnswerRouteRecordDAO.getCountByReportIdAndRouteDetailId(reportId, routeDetailId);
                        if (count == 0L) {
                            FusAnswerRouteRecord record = new FusAnswerRouteRecord();
                            record.setReportId(reportId);
                            record.setRouteDetailId(routeDetailId);
                            record.setGmtCreate(now);
                            fusAnswerRouteRecordDAO.save(record);
                        }
                    }
                }
            }
        }
    }

    /**
     * @param routeId
     * @param followUpRecordsContents
     * @throws
     * @description: 处理随访内容详情
     * @return: void
     * @author: tongtp
     * @date: 2020/7/28 17:43
     */
    private void handleFollowUpRecordsContents(Long routeId, Long routeDetailId, List<FollowUpRecordsContent> followUpRecordsContents,
                                               List<FollowUpRecordsRequisition> requisitions,
                                               List<FollowUpRecordsEducation> educations) {

        //查询所有路径详情内容
        List<FollowUpRouteDetailContent> followUpRouteDetailContents = followUpRouteDetailContentDAO.queryByRouteDetailId(routeDetailId);

        if (CommonUtils.isNotEmpty(followUpRouteDetailContents)) {
            for (FollowUpRouteDetailContent followUpRouteDetailContent : followUpRouteDetailContents) {
                FollowUpRecordsContent followUpRecordsContent = new FollowUpRecordsContent();
                followUpRecordsContents.add(followUpRecordsContent);

                followUpRecordsContent.setIndexType(followUpRouteDetailContent.getIndexType());
                followUpRecordsContent.setIndexClassifyId(followUpRouteDetailContent.getIndexClassifyId());
                followUpRecordsContent.setIndexClassifyName(followUpRouteDetailContent.getIndexClassifyName());
                followUpRecordsContent.setBusinessId(followUpRouteDetailContent.getBusinessId());
                followUpRecordsContent.setBusinessName(followUpRouteDetailContent.getBusinessName());
                followUpRecordsContent.setProjectDetails(followUpRouteDetailContent.getProjectDetails());
                followUpRecordsContent.setFollowUpDetail(followUpRouteDetailContent.getFollowUpDetail());
            }
        }

        //查询所有路径详情的表单和健康宣教
        List<FollowUpRouteDetailForm> followUpRouteDetailForms =
                followUpRouteDetailFormDAO.queryByRouteDetailId(routeDetailId);
        if (CommonUtils.isNotEmpty(followUpRouteDetailForms)) {
            for (FollowUpRouteDetailForm followUpRouteDetailForm : followUpRouteDetailForms) {

                //1 表单 2 推荐科室 3 健康宣教 4 健康监测
                Byte itemType = followUpRouteDetailForm.getItemType();
                //表单
                if (itemType.equals((byte) 1)) {
                    FollowUpRecordsRequisition r = new FollowUpRecordsRequisition();
                    r.setQuestionnaireId(followUpRouteDetailForm.getFormRecordId());
                    r.setQuestionnaireName(followUpRouteDetailForm.getFormName());
                    requisitions.add(r);
                } else if (itemType.equals((byte) 3)) {
                    //宣教
                    FollowUpRecordsEducation e = new FollowUpRecordsEducation();
                    e.setEducationId(followUpRouteDetailForm.getEducationId());
                    e.setEducationName(followUpRouteDetailForm.getEducationName());
                    e.setDefaultPush(0);
                    educations.add(e);
                } else {
                    FollowUpRecordsContent followUpRecordsContent = new FollowUpRecordsContent();
                    followUpRecordsContents.add(followUpRecordsContent);
                    followUpRecordsContent.setEducationId(followUpRouteDetailForm.getEducationId());
                    followUpRecordsContent.setEducationName(followUpRouteDetailForm.getEducationName());
                    followUpRecordsContent.setQuestionnaireId(followUpRouteDetailForm.getFormRecordId());
                    followUpRecordsContent.setQuestionnaireName(followUpRouteDetailForm.getFormName());
                }
            }
        }
    }

    /**
     * @param diseaseTypeId
     * @param followUpRouteDetail
     * @param routeDetailId
     * @param intervalTime
     * @param followUpFrequencyTime
     * @throws
     * @description: 计算得到随访间隔时间-天数
     * @return: java.lang.Integer
     * @author: tongtp
     * @date: 2020/7/28 17:40
     */
    private Integer getIntervalTime(Long diseaseTypeId, FollowUpRouteDetail followUpRouteDetail,
                                    Long routeDetailId, Integer intervalTime, Byte followUpFrequencyTime) {
        switch (followUpFrequencyTime) {
            case (byte) 1:
                intervalTime = 1;
                break;
            case (byte) 2:
                intervalTime = 7;
                break;
            case (byte) 3:
                intervalTime = 28;
                break;
            case (byte) 4:
                intervalTime = 30;
                break;
            case (byte) 5:
                intervalTime = 90;
                break;
            case (byte) 6:
                intervalTime = 180;
                break;
            case (byte) 7:
                intervalTime = 365;
                break;
            default:
                break;
        }
        if (intervalTime == 0) {
            logger.info("diseaseTypeId:{},RouteDetailId:{}," +
                            "FollowUpFrequency:{}，FollowUpFrequencyTime:{},长期随访计划时间间隔为0，暂停生成计划",
                    diseaseTypeId,
                    routeDetailId, followUpRouteDetail.getFollowUpFrequency(),
                    followUpFrequencyTime);
            return null;
        }
        return intervalTime;
    }


    /**
     * @param diseaseTypeId
     * @param messageBuilder
     * @param operatorId
     * @throws
     * @description: 根据病种id生成执行计划
     * @return: void
     * @author: tongtp
     * @date: 2020/9/29 10:24
     */
    private void produceExecutionListByDiseaseTypeId(Long diseaseTypeId,
                                                     StringBuilder messageBuilder, String operatorId) throws ControllerException {
        List<FollowUpRoute> followUpRoutes = followUpRouteDAO.queryByDiseaseTypeId(diseaseTypeId);
        if (!CollectionUtils.isEmpty(followUpRoutes)) {
            for (FollowUpRoute followUpRoute :
                    followUpRoutes) {
                BaseResponse baseResponse = doProduceExecutionList(followUpRoute, operatorId);
                if (baseResponse != null) {
                    messageBuilder.append(baseResponse.getMessage() + "\n");
                }
            }
        }
    }


    /**
     * 随访路径中设置的提前通知时间
     */
    @Override
    @RpcService
    public void autoFollowUpRecords() {
        String date = DateUtil.format3.format(new Date());
        Date time = new Date();
        try {
            time = DateUtil.format3.parse(date);
        } catch (ParseException e) {
            logger.error("autoFollowUpRecords,ParseException:", e);
        }
        //============================推送专病随访的随访任务start============================
        List<FollowUpRecords> followUpRecords = followUpRecordsDAO.queryNoticeRecords(time);
        if (CommonUtils.isNotEmpty(followUpRecords)) {
            for (FollowUpRecords follow : followUpRecords) {
                Boolean flag = sendMsgService.sendMessage(JSONObject.toJSON(follow), true, 2);
                if (flag) {
                    follow.setNotifyStatus((byte) 1);
                    followUpRecordsDAO.update(follow);
                    logger.info("推送专病随访的随访任务RecordId:{},推送成功", follow.getRecordId());
                } else {
                    logger.info("推送专病随访的随访任务RecordId:{},推送失败", follow.getRecordId());
                }
            }
        }
        //将前一天已推送的居民未执行的
        Date dateYesterday = DateUtils.dateSub(new Date(), 1);
        Date yesterday = DateUtils.toDate(DateUtils.toString(dateYesterday, "yyyy-MM-dd"));
        followUpRecords = followUpRecordsDAO.queryNoticeRecordsYesterday(yesterday);
        if (CommonUtils.isNotEmpty(followUpRecords)) {
            for (FollowUpRecords follow : followUpRecords) {
                Boolean flag = sendMsgService.sendMessage(JSONObject.toJSON(follow), true, 2);
                if (flag) {
                    logger.info("将前一天已推送的居民未执行的-推送专病随访的随访任务RecordId:{},推送成功", follow.getRecordId());
                } else {
                    logger.info("将前一天已推送的居民未执行的-推送专病随访的随访任务RecordId:{},推送失败", follow.getRecordId());
                }
            }
        }
        //============================推送专病随访的随访任务end============================
        //============================推送院后随访的随访任务start============================
        List<FusAfterHosRecord> fusAfterHosRecords = fusAfterHosRecordDAO.queryNoticeRecords(time);
        if (CommonUtils.isNotEmpty(fusAfterHosRecords)) {
            for (FusAfterHosRecord follow : fusAfterHosRecords) {
                Boolean flag = sendMsgService.sendMessage(JSONObject.toJSON(follow), true, 2);
                if (flag) {
                    follow.setNotifyStatus(1);
                    fusAfterHosRecordDAO.update(follow);
                    logger.info("推送院后随访的随访任务RecordId:{},推送成功", follow.getRecordId());
                } else {
                    logger.info("推送院后随访的随访任务RecordId:{},推送失败", follow.getRecordId());
                }
            }
        }
        //将前一天已推送的居民未执行的
        fusAfterHosRecords = fusAfterHosRecordDAO.queryNoticeRecordsYesterday(yesterday);
        if (CommonUtils.isNotEmpty(fusAfterHosRecords)) {
            for (FusAfterHosRecord follow : fusAfterHosRecords) {
                Boolean flag = sendMsgService.sendMessage(JSONObject.toJSON(follow), true, 2);
                if (flag) {
                    logger.info("将前一天已推送的居民未执行的-推送院后随访的随访任务RecordId:{},推送成功", follow.getRecordId());
                } else {
                    logger.info("将前一天已推送的居民未执行的-推送院后随访的随访任务RecordId:{},推送失败", follow.getRecordId());
                }
            }
        }
        //============================推送院后随访的随访任务end============================
    }

    /**
     * 根据随访计划id和宣教id更新宣教阅读状态
     *
     * @param resultRequest
     */
    @Override
    @RpcService
    public void updateFollowUpContentStatus(SaveFollowUpResultRequest resultRequest) throws ControllerException {
        followUpRecordsEducationDAO.updateEducationStatus(resultRequest.getRecordId(), Long.valueOf(resultRequest.getEducationId()), new Date());

        Long unread = followUpRecordsEducationDAO.getCountContentByRecordId(resultRequest.getRecordId());
        //若状态都为已读，则修改随访计划状态为以执行
        if (unread <= Constants.ZORE) {
            FollowUpRecords followUpRecords = new FollowUpRecordsVO();
            followUpRecords.setRecordId(resultRequest.getRecordId());
            followUpRecords.setResultCode(Byte.valueOf(Constants.ONE_STRING));
            followUpRecords.setFollowUpStatus(Byte.valueOf(Constants.ONE_STRING));
            followUpRecords.setExecuteId(resultRequest.getOperatorId());
            followUpRecords.setExecuteName(resultRequest.getOperatorName());
            followUpRecords.setExecuteTime(new Date());
            followUpRecords.setGmtModified(new Date());
            followUpRecordsDAO.updateFollowUpRecordsResult(followUpRecords);

            if (FollowUpStatusEnum.FINISH.getStatus() == followUpRecords.getFollowUpStatus()
                    || FollowUpStatusEnum.SUSPEND.getStatus() == followUpRecords.getFollowUpStatus()
                    || FollowUpStatusEnum.CANCEL.getStatus() == followUpRecords.getFollowUpStatus()) {
                //生成下一次随访计划
                createNextFollowUpRecords(followUpRecords);
            }
        }
    }

    /**
     * 修改随访问卷
     *
     * @param resultRequest
     */
    @RpcService
    public void updateQuestionnaireId(SaveFollowUpResultRequest resultRequest) {
        if (CommonUtils.isNotEmpty(resultRequest.getRecordId()) && CommonUtils.isNotEmpty(resultRequest.getQuestionnaireId())) {
            FollowUpRecords followUpRecords = followUpRecordsDAO.get(resultRequest.getRecordId());
            if (null != followUpRecords) {
                followUpRecords.setMedicalRecordId(resultRequest.getQuestionnaireId());
                followUpRecords.setMedicalRecordName(resultRequest.getQuestionnaireName());
                followUpRecordsDAO.update(followUpRecords);
            }
        }
    }


    /**
     * 根据随访计划id更新随访计划异常查看状态为已读状态
     *
     * @param resultRequest
     */
    @Override
    @RpcService
    public void updateAbnormalReadFlag(SaveFollowUpResultRequest resultRequest) {
        if (CommonUtils.isNotEmpty(resultRequest.getRecordId())) {
            followUpRecordsDAO.updateAbnormalReadFlag(resultRequest.getRecordId());
        }
        if (StringUtils.isNotEmpty(resultRequest.getHmDiseaseRelationId())) {
            odsHmDiseaseRelationDAO.updateAbnormalReadFlag(resultRequest.getHmDiseaseRelationId());
        }
    }

    /**
     * 批量更新随访状态
     *
     * @param resultRequest
     */
    @Override
    @RpcService
    public void batchUpdateFollowUpContentStatus(SaveFollowUpResultRequest resultRequest) throws ControllerException {
        followUpRecordsDAO.updateFollowUpStastusByIds(resultRequest.getRecordIdList(),
                resultRequest.getFollowUpStatus());

        if (FollowUpStatusEnum.FINISH.getStatus() == resultRequest.getFollowUpStatus()
                || FollowUpStatusEnum.SUSPEND.getStatus() == resultRequest.getFollowUpStatus()
                || FollowUpStatusEnum.CANCEL.getStatus() == resultRequest.getFollowUpStatus()) {
            if (CommonUtils.isNotEmpty(resultRequest.getRecordIdList())) {
                for (Long aLong : resultRequest.getRecordIdList()) {
                    FollowUpRecords followUpRecords = followUpRecordsDAO.get(aLong);
                    //生成下一次随访计划
                    createNextFollowUpRecords(followUpRecords);
                }
            }

        }
    }

    /**
     * 根据随访计划id查询健康宣教
     *
     * @param request 随访计划id
     * @return 健康宣教
     */
    @Override
    @RpcService
    public List<FollowUpRecordsEducation> queryFollowUpContentById(SaveFollowUpResultRequest request) {
        return followUpRecordsContentDAO.queryFollowUpContentById(request.getRecordId());
    }

    /**
     * 查询随访记录关联的门诊或住院记录列表
     *
     * @param request 入参
     * @return 记录信息列表
     */
    @Override
    @RpcService
    public List<PatientMedicalDataCollectResponse> queryVisitMedicalList(PatientMedicalDataRequest request) {

        if (CommonUtils.isNotEmpty(request.getFollowUpRecordId())) {
            PatientMedicalDataCollectEntity collectEntity = patientMedicalDataCollectDAO.getRecordIdByFollowUpRecordId(request.getFollowUpRecordId());
            if (collectEntity != null && CommonUtils.isNotEmpty(collectEntity.getRecordId())) {
                request.setBusinessId(collectEntity.getRecordId());
            }
        }

        //查询门诊或住院记录
        List<PatientMedicalDataCollectResponse> collectResponseList = patientMedicalDataCollectDAO.queryPatientMedicalDataListByCardAndDiseaseId(request);
        if (CommonUtils.isEmpty(collectResponseList)) {
            return collectResponseList;
        }
        //查询处置
        for (PatientMedicalDataCollectResponse response : collectResponseList) {
            //没机构名称时补充展示
            if (StringUtils.isEmpty(response.getOrganizationName()) && StringUtils.isNotEmpty(response.getOrganizationId())) {
                Organization organization = organizationRpcService.getOrgDetailByOrgCode(response.getOrganizationId());
                response.setOrganizationName(organization.getFullName());
            }

            List<Map<String, Object>> treatmentList = patientMedicalDataCollectDAO.queryTreatmentListBybusinessId(response.getRecordId());
            if (CommonUtils.isEmpty(treatmentList)) {
                continue;
            }
            String itemNames = "";
            for (Map<String, Object> map : treatmentList) {
                itemNames = itemNames + map.get("itemName") + ";";
            }
            response.setItemNames(itemNames);
        }
        return collectResponseList;
    }

    /**
     * 查询门诊、住院记录Id查询门诊、住院表单填写的信息
     *
     * @param request 入参
     * @return 记录信息列表
     */
    @Override
    @RpcService
    public FormFillingInfoResponse queryFormFillingInfoList(PatientMedicalDataRequest request) {
        if (StringUtils.isEmpty(request.getBusinessId()) || StringUtils.isEmpty(request.getRecordType())) {
            return null;
        }
        FormFillingInfoResponse response = new FormFillingInfoResponse();
        if (Constants.ONE_STRING.equals(request.getRecordType())) {
            //门诊记录
            VrOutpatientVisitRecord outpatientVisitRecord = patientMedicalDataCollectDAO.queryVisitRecordBybusinessId(request.getBusinessId());
            response.setOutpatientVisitRecord(outpatientVisitRecord);
        } else {
            //住院记录
            VrInpatientVisitRecordVo inpatientVisitRecord = patientMedicalDataCollectDAO.queryInpatientRecordBybusinessId(request.getBusinessId());
            if (CommonUtils.isNotEmpty(inpatientVisitRecord)) {
                List<VrVisitDiagnosis> diagnosisList = vrVisitDiagnosisDAO.queryVrVisitDiagnosisByBusinessId(request.getBusinessId());
                if (CommonUtils.isNotEmpty(diagnosisList)) {
                    String diseasesCode = "";
                    String diseasesName = "";
                    for (VrVisitDiagnosis diagnosis : diagnosisList) {
                        diseasesCode = diagnosis.getDiseasesCode() + ";" + diseasesCode;
                        diseasesName = diagnosis.getDiseasesName() + ";" + diseasesName;
                    }
                    if (StringUtils.isNotEmpty(diseasesCode)) {
                        inpatientVisitRecord.setAdmissionDiagnosis(diseasesCode.substring(0, diseasesCode.length() - 1));
                    }
                    if (StringUtils.isNotEmpty(diseasesName)) {
                        inpatientVisitRecord.setAdmissionDiagnosis(diseasesName.substring(0, diseasesName.length() - 1));
                    }
                }
                if (StringUtils.isEmpty(inpatientVisitRecord.getOrganizationName())) {
                    Organization organization = organizationRpcService.getOrgDetailByOrgCode(inpatientVisitRecord.getOrganizationId());
                    if (CommonUtils.isNotEmpty(organization)) {
                        inpatientVisitRecord.setOrganizationName(organization.getFullName());
                    }
                }
                response.setInpatientVisitRecord(inpatientVisitRecord);
            }

        }
        //检验
        List<InspectResponse> inspectReportList = patientMedicalDataCollectDAO.queryInspectListBybusinessId(request.getBusinessId());
        response.setInspectReportList(inspectReportList);
        //检查
        List<ExamReportVo> examReportList = patientMedicalDataCollectDAO.queryExamReportListBybusinessId(request.getBusinessId());
        response.setExamReportList(examReportList);
        //用药
        List<PrescriptionRecordEntity> prescriptionRecordList = patientMedicalDataCollectDAO.queryPrescriptionListBybusinessId(request.getBusinessId());
        response.setPrescriptionRecordList(prescriptionRecordList);
        //处置
        List<Map<String, Object>> treatmentList = patientMedicalDataCollectDAO.queryTreatmentListBybusinessId(request.getBusinessId());
        response.setTreatmentList(treatmentList);
        //手术
        List<VrSurgicalRecord> surgicalRecordList = patientMedicalDataCollectDAO.querySurgicalListBybusinessId(request.getBusinessId());
        response.setSurgicalRecordList(surgicalRecordList);
        return response;
    }

    /**
     * 暂挂
     */
    @RpcService
    @Override
    public void hangUpPlan(FollowUpHangUpDTO dto) {
        //增加暂挂记录
        FusAfterPendingRecord insert = new FusAfterPendingRecord();
        insert.setId(KeyGenerator.randomGenerate());
        insert.setRecordId(dto.getRecordId());
        insert.setFollowType(FollowTypeEnum.FUS_SPECIALIST.getType());
        insert.setExecuteId(dto.getExecuteId());
        insert.setExecuteName(dto.getExecuteName());
        insert.setDepartmentId(dto.getExecuteDeptId());
        insert.setDeptName(dto.getExecuteDeptName());
        insert.setPendingType(dto.getPendingType());
        insert.setPendingDetail(dto.getExecuteDetail());
        insert.setCreateDt(new Date());
        insert.setModifyDt(new Date());
        fusAfterPendingRecordDAO.insertSelective(insert);
    }

    /**
     * 获取暂挂列表
     *
     * @param recordId 随访记录id
     */
    @RpcService
    @Override
    public List<HangUpFollowUpListVO> hangUpRecords(String recordId) {

        if (org.springframework.util.StringUtils.isEmpty(recordId)) {
            throw new ServiceException("随访记录id不能为空");
        }
        FusAfterPendingRecord query = new FusAfterPendingRecord();
        query.setRecordId(recordId);
        query.setFollowType(FollowTypeEnum.FUS_SPECIALIST.getType());
        List<FusAfterPendingRecord> records = fusAfterPendingRecordDAO.selectList(query);
        if (CollectionUtils.isEmpty(records)) {
            return Collections.emptyList();
        }
        return records.stream().map(r -> {
            HangUpFollowUpListVO vo = new HangUpFollowUpListVO();
            ctd.util.BeanUtils.copy(r, vo);
            return vo;
        }).sorted((r1, r2) -> {
            Date createDt1 = r1.getCreateDt();
            Date createDt2 = r2.getCreateDt();
            return createDt1.compareTo(createDt2);
        }).collect(Collectors.toList());
    }

    /**
     * 获取随访
     */
    @RpcService
    @Override
    public FusAfterContacts getContacts(FollowUpQueryContactsDTO dto) {
        FusAfterContacts query = new FusAfterContacts();
        query.setTenantId(UserRoleToken.getCurrentTenantId());
        query.setOrganizationId(dto.getOrganizationId());
        query.setPatientId(dto.getPatientId());
        return fusAfterContactsDAO.selectOne(query);
    }

    /**
     * 保存随访联系人 所有随访通用
     */
    @RpcService
    @Override
    public void saveContacts(FollowUpSaveContactsDTO dto) {
        String tenantId = UserRoleToken.getCurrentTenantId();
        Date now = new Date();
        FusAfterContacts query = new FusAfterContacts();
        query.setTenantId(tenantId);
        query.setOrganizationId(dto.getOrganizationId());
        query.setPatientId(dto.getPatientId());
        FusAfterContacts contacts = fusAfterContactsDAO.selectOne(query);
        FusAfterContacts insertOrUpdate = new FusAfterContacts();
        insertOrUpdate.setContactsName(dto.getContactsName());
        insertOrUpdate.setContactsRemark(dto.getContactsRemark());
        insertOrUpdate.setContactsPhone(dto.getContactsPhone());
        insertOrUpdate.setContactsRelation(dto.getContactsRelation());
        insertOrUpdate.setPatientId(dto.getPatientId());
        insertOrUpdate.setOrganizationId(dto.getOrganizationId());
        insertOrUpdate.setTenantId(tenantId);
        insertOrUpdate.setModifyDt(now);
        if (Objects.isNull(contacts)) {
            insertOrUpdate.setId(KeyGenerator.randomGenerate());
            insertOrUpdate.setCreateDt(now);
            fusAfterContactsDAO.insertSelective(insertOrUpdate);
        } else {
            insertOrUpdate.setId(contacts.getId());
            fusAfterContactsDAO.updateSelective(insertOrUpdate);
        }
    }

    /**
     * 删除随访关联表单
     */
    @RpcService
    @Override
    public void deleteForm(DeleteFollowUpFormDTO dto) {
        String formId = dto.getFormId();
        String eduFormId = dto.getEduFormId();
        if (StringUtils.isNotEmpty(formId)) {
            followUpRecordsRequisitionDAO.remove(formId);
        }
        if (CommonUtils.isNotEmpty(dto.getFormIds())){
            followUpRecordsRequisitionDAO.removeByFormIds(dto.getFormIds());
        }
        if (StringUtils.isNotEmpty(eduFormId)) {
            followUpRecordsEducationDAO.remove(eduFormId);
        }
        if (CommonUtils.isNotEmpty(dto.getEduFormIds())){
            followUpRecordsEducationDAO.removeByEduFormIds(dto.getEduFormIds());
        }
    }

    /**
     * 新增随访关联表单
     */
    @RpcService
    @Override
    public void addForm(SaveFollowUpFormDTO dto) {
        Long recordId = Long.parseLong(dto.getRecordId());
        UserAllVo userInfo = getCurrentUserInfo();
        List<FollowUpQuestionnaireDTO> questionnaireList = dto.getQuestionnaireList();
        //保存随访表单
        if (!CollectionUtils.isEmpty(questionnaireList)) {
            questionnaireList.forEach(q -> saveOrUpdateQuestionnaire(q, userInfo, recordId));
        }

        //保存健康宣教
        List<FollowUpEducationDTO> educationList = dto.getEducationList();
        if (!CollectionUtils.isEmpty(educationList)) {
            educationList.forEach(e -> saveOrUpdateEducation(e, recordId));
        }
    }

    /**
     * 保存随访关联表单
     */
    @RpcService
    @Override
    public void saveForm(FollowUpQuestionnaireDTO dto) {
        String answerAbnormal = dto.getAnswerAbnormal();
        String formId = dto.getFormId();
        FollowUpRecordsRequisition inOrUp = new FollowUpRecordsRequisition();
        inOrUp.setUserInfoId(dto.getUserInfoId());
        inOrUp.setRecordId(dto.getRecordId());
        inOrUp.setAnswerAbnormal(answerAbnormal);
        inOrUp.setQuestionnaireId(dto.getQuestionnaireId());
        inOrUp.setQuestionnaireName(dto.getQuestionnaireName());
        inOrUp.setModifyDt(new Date());
        if(StringUtils.isEmpty(formId)){
            inOrUp.setFormId(KeyGenerator.randomGenerate());
            inOrUp.setCreateDt(new Date());
            followUpRecordsRequisitionDAO.insertSelective(inOrUp);
        }else{
            inOrUp.setFormId(formId);
            followUpRecordsRequisitionDAO.updateSelective(inOrUp);
        }


        if ("1".equals(answerAbnormal)) {
            //更新主表异常状态
            FollowUpRecordsRequisition requisition = followUpRecordsRequisitionDAO.get(formId);
            if(Objects.isNull(requisition)){
                return;
            }
            Long recordId = requisition.getRecordId();
            FollowUpRecords u = new FollowUpRecords();
            u.setRecordId(recordId);
            u.setAnswerAbnormal(answerAbnormal);
            followUpRecordsDAO.updateSelective(u);
        }
    }


    /**
     * 保存随访表单
     */
    private void saveOrUpdateQuestionnaire(FollowUpQuestionnaireDTO dto, UserAllVo userInfo, Long recordId) {
        String formId = dto.getFormId();

        FollowUpRecordsRequisition insertOrUpdate = new FollowUpRecordsRequisition();

        insertOrUpdate.setRecordId(recordId);
        insertOrUpdate.setCreateId(userInfo.getUserId());
        insertOrUpdate.setExecuteId(userInfo.getUserId());
        insertOrUpdate.setExecuteName(userInfo.getUserName());

        String questionnaireId = dto.getQuestionnaireId();
        if (org.springframework.util.StringUtils.isEmpty(questionnaireId)) {
            return;
        }
        insertOrUpdate.setQuestionnaireId(questionnaireId);
        insertOrUpdate.setQuestionnaireName(dto.getQuestionnaireName());
        insertOrUpdate.setUserInfoId(dto.getUserInfoId());
        Date now = new Date();
        if (org.springframework.util.StringUtils.isEmpty(formId)) {
            //新增
            insertOrUpdate.setFormId(KeyGenerator.randomGenerate());
            insertOrUpdate.setCreateDt(now);
            insertOrUpdate.setModifyDt(now);
            followUpRecordsRequisitionDAO.insertSelective(insertOrUpdate);
        } else {
            //更新
            insertOrUpdate.setFormId(formId);
            insertOrUpdate.setModifyDt(now);
            followUpRecordsRequisitionDAO.updateSelective(insertOrUpdate);
        }
    }

    /**
     * 保存健康宣教
     */
    private void saveOrUpdateEducation(FollowUpEducationDTO dto, Long recordId) {

        String id = dto.getId();

        FollowUpRecordsEducation insertOrUpdate = new FollowUpRecordsEducation();
        Long educationId = dto.getEducationId();
        if (Objects.isNull(educationId)) {
            return;
        }
        insertOrUpdate.setEducationId(educationId);
        insertOrUpdate.setRecordId(recordId);
        insertOrUpdate.setDefaultPush(0);
        insertOrUpdate.setEducationName(dto.getEducationName());

        Date now = new Date();
        insertOrUpdate.setModifyDt(now);
        if (org.springframework.util.StringUtils.isEmpty(id)) {
            insertOrUpdate.setId(KeyGenerator.randomGenerate());
            insertOrUpdate.setCreateDt(now);
            followUpRecordsEducationDAO.insertSelective(insertOrUpdate);
        } else {
            insertOrUpdate.setId(id);
            followUpRecordsEducationDAO.updateSelective(insertOrUpdate);
        }
    }

    private UserAllVo getCurrentUserInfo() {
        UserAllVo userAllVo = baseDeviceService.getAllByOnline();
        if (Objects.isNull(userAllVo)) {
            throw new ServiceException("获取当前用户信息失败");
        }

        return userAllVo;
    }
}
